package com.yanqu.road.server.channelserver.manager.activity.tonbing.activity;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.activityunion.ActivityUnionInfo;
import com.yanqu.road.entity.activity.activityunion.ActivityUnionMemberInfo;
import com.yanqu.road.entity.activity.tonbingchannel.ChannelTonBingRankSort;
import com.yanqu.road.entity.activity.tonbingchannel.config.ChannelTonBingCampBoxConfig;
import com.yanqu.road.entity.activity.tonbingchannel.config.ChannelTonBingCityConfig;
import com.yanqu.road.entity.activity.tonbingchannel.config.ChannelTonBingTitleConfig;
import com.yanqu.road.entity.activity.tonbingchannel.data.*;
import com.yanqu.road.entity.activity.tonbingchannel.join.ChannelTonBingUnionJoin;
import com.yanqu.road.entity.activity.tonbingchannel.join.ChannelTonBingUnionJoinMember;
import com.yanqu.road.entity.log.channel.channeltongbing.LogChannelTonBingAppoint;
import com.yanqu.road.entity.log.channel.channeltongbing.LogChannelTonBingJoin;
import com.yanqu.road.entity.log.channel.channeltongbing.LogChannelTonBingLockUnion;
import com.yanqu.road.entity.log.channel.channeltongbing.LogChannelTonBingUnionPeak;
import com.yanqu.road.entity.enums.activity.tonbing.eTonBingPosition;
import com.yanqu.road.entity.enums.activity.tonbing.eTonBingRedDotType;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eMessageType;
import com.yanqu.road.entity.enums.eSceneType;
import com.yanqu.road.entity.enums.eUnionPosition;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.scene.UserScene;
import com.yanqu.road.entity.union.UnionBaseInfo;
import com.yanqu.road.logic.bussiness.activity.ChannelTonBingActivityBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.ChannelTonBingPb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.logic.pb.UnionBasePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.activity.ChannelTonBingProto;
import com.yanqu.road.pb.cross.activity.CrossActivityProto;
import com.yanqu.road.pb.rank.RankProto;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.channelserver.logic.ChannelMessageHelper;
import com.yanqu.road.server.channelserver.manager.activity.ChannelActivityUnionMgr;
import com.yanqu.road.server.channelserver.manager.activity.tonbing.logic.ChannelTonBingChatLogic;
import com.yanqu.road.server.channelserver.manager.activity.tonbing.task.BaseChannelTonBingActivityTask;
import com.yanqu.road.server.channelserver.manager.activity.tonbing.task.impl.ChannelTonBingLockUnionTask;
import com.yanqu.road.server.channelserver.manager.activity.tonbing.task.impl.ChannelTonBingMakeMatchTask;
import com.yanqu.road.server.channelserver.manager.activity.tonbing.task.impl.ChannelTonBingSetWinnerTask;
import com.yanqu.road.server.channelserver.manager.scene.ChannelSceneMgr;
import com.yanqu.road.server.channelserver.manager.user.ChannelUserMgr;
import com.yanqu.road.server.manager.activity.ActivityMgr;
import com.yanqu.road.server.manager.log.ChannelAutoLogMgr;
import com.yanqu.road.server.protocol.*;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class ChannelTonBingActivity extends ChannelTonBingBaseAc {

    private RandomHelper randomHelper = new RandomHelper();

    private AtomicInteger matchId = new AtomicInteger(1);

    /**
     * 活动总数据
     */
    private ChannelTonBingDataMain channelTonBingDataMain;

    /**
     * 轮次,战场，比赛id
     */
    private Map<Integer, Map<Integer, Map<Integer, ChannelTonBingMatch>>> turnMatchMap = new ConcurrentHashMap<>();

    //缓存所有玩家的所在场次信息
    private Map<Long, ChannelTonBingMatch> userMatchMap = new ConcurrentHashMap<>();

    //matchId
    private Map<Integer, ChannelTonBingMatch> matchMap = new ConcurrentHashMap<>();


    /**
     * 商会数据
     */
    private Map<String, ChannelTonBingUnionJoin> unionJoinMap = new ConcurrentHashMap<>();

    /**
     * 玩家数据
     */
    private Map<Long, ChannelTonBingUserData> userDataMap = new ConcurrentHashMap<>();

    /**
     * 阵营数据
     */
    private Map<Integer, ChannelTonBingCampData> campDataMap = new ConcurrentHashMap<>();

    //userId matchId
    private Map<Long, Integer> watchMap = new ConcurrentHashMap<>();


    //获得每个阵营第一名的战功玩家
    public Map<Integer, Long> getCampMaxZhanGongUnionUserIdMap() {
        Map<Integer, Long> campIdUserIdMap = new ConcurrentHashMap<>();
        for (int campId : campUserRankMap.keySet()) {
            long userId = 0;
            ChannelTonBingRankListModel rankListModel = campUnionRankMap.get(campId);
            if (rankListModel != null) {
                LinkedList<ChannelTonBingRank> rankList = rankListModel.getRankList();
                if (!rankList.isEmpty()) {
                    ChannelTonBingRank first = rankList.getFirst();
                    ChannelTonBingUnionJoin join = getUnionJoin(first.getId());
                    if (join != null) {
                        for (ChannelTonBingUnionJoinMember member : join.getMemberMap().values()) {
                            if (member.getPosition() == eUnionPosition.Master.getValue()) {
                                userId = member.getUserId();
                                break;
                            }
                        }
                    }
                }
            }
            campIdUserIdMap.put(campId, userId);
            if (userId != 0) {
                ChannelTonBingUserData userData = getUserData(userId);
                if (userData == null) {
                    continue;
                }
                Map<Integer, Integer> posMap = userData.getPositionMap();
                posMap.put(userData.getCampId(), eTonBingPosition.Master.getValue());
                Map<Integer, Integer> appointMap = new ConcurrentHashMap<>();
                appointMap.put(userData.getCampId(), eTonBingPosition.Master.getValue());
                userData.setPositionMap(posMap);
                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
                if (userBaseInfo != null) {
                    ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.Builder crespMsg = ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.newBuilder();
                    crespMsg.setWinerName("");
                    parsePosAppoint(crespMsg, appointMap);
                    crespMsg.setCampId(userData.getCampId());
                    crespMsg.setSendReward(true);
                    sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_CITY_APPOINT_POSITION, crespMsg, userData);
                }
            }
        }
        return campIdUserIdMap;
    }

    /**
     * 设置城主
     */
    public void channelTonBingSetWinnerTask() {
        // 已经设置城主
        if (channelTonBingDataMain.getWinnerMap().size() != 0L) {
            return;
        }
        // 时间未到
        long nowTime = System.currentTimeMillis();
        if (nowTime < config.getActivityInfo().getEndTime() * 1000L) {
            addTask(new ChannelTonBingSetWinnerTask(this, config.getActivityInfo().getEndTime() * 1000L));
            return;
        }
        // 时间过了
        if (nowTime > config.getActivityInfo().getEndShowTime() * 1000L) {
            return;
        }
        int lastTurn = config.getLastTurn();
        int lastWarType = config.getLastWayType();
        //没找到这一轮
        if (!turnMatchMap.containsKey(lastTurn)) {
            return;
        }
        //没找到这个战场
        if (!turnMatchMap.get(lastTurn).containsKey(lastWarType)) {
            return;
        }
        Map<Integer, ChannelTonBingMatch> matchMap = turnMatchMap.get(lastTurn).get(lastWarType);
        //原则上只能有一个分组，多了就不玩了
        if (matchMap.size() != 1) {
            return;
        }
        for (ChannelTonBingMatch match : matchMap.values()) {
            // 正常设置
            Map<Integer, ChannelTonBingCityConfig> cityConfigMap = config.getCityConfigMap(match.getChannelTonBingData().getWarType());
            for (ChannelTonBingCityConfig cityConfig : cityConfigMap.values()) {
                if (cityConfig.getType() == 6) {
                    Map<Integer, ChannelTonBingCity> cityMap = match.getChannelTonBingData().getCityMap();
                    ChannelTonBingCity cityData = cityMap.get(cityConfig.getId());
                    int campId = cityData.getCampId();
                    long winnerUserId = 0L;
                    if (campId == 0) {
                        // 没有城主
                        logger.error("ton bing activityId {} no winner!", config.getActivityInfo().getActivityId());
                        winnerUserId = getMaxZhanGongUserId();
                    } else {
                        winnerUserId = match.getCampMaxZhanGongUserId(campId);
                    }
                    Map<Integer, Long> campIdUserIdMap = match.getCampMaxZhanGongUnionUserIdMap();
                    campIdUserIdMap.put(0, winnerUserId);
                    channelTonBingDataMain.setWinnerMap(campIdUserIdMap);
                    if (winnerUserId != 0) {
                        ChannelTonBingUserData userData = getUserData(winnerUserId);
                        Map<Integer, Integer> posMap = userData.getPositionMap();
                        //可能任命多个，只发一个的奖励
                        Map<Integer, Integer> appointMap = new ConcurrentHashMap<>();
                        posMap.put(0, eTonBingPosition.Master.getValue());
                        appointMap.put(0, eTonBingPosition.Master.getValue());
                        userData.setPositionMap(posMap);
                        UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(winnerUserId);
                        if (userBaseInfo != null) {
                            ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.Builder crespMsg = ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.newBuilder();
                            crespMsg.setWinerName("");
                            parsePosAppoint(crespMsg, appointMap);
                            crespMsg.setCampId(userData.getCampId());
                            crespMsg.setSendReward(true);
                            //別一启动就来这里，会发送失败
                            sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_CITY_APPOINT_POSITION, crespMsg, userData);
                        }
                    }
                    syncWinnerGetNotice();
                    Map<Integer, Long> winnerMap = channelTonBingDataMain.getWinnerMap();
                    for (long userId : winnerMap.values()) {
                        addRedDot(getUserData(userId), eTonBingRedDotType.Type12_BeAppoint);
                        addRedDot(getUserData(userId), eTonBingRedDotType.Type11_Appoint);
                    }
                    return;
                }
            }
        }
        Map<Integer, Long> winnerMap = channelTonBingDataMain.getWinnerMap();
        for (long userId : winnerMap.values()) {
            addRedDot(getUserData(userId), eTonBingRedDotType.Type12_BeAppoint);
            addRedDot(getUserData(userId), eTonBingRedDotType.Type11_Appoint);
        }
    }


    //城池有了同步客户端告诉他要出图标了
    public void syncWinnerGetNotice() {
        ChannelTonBingProto.ChannelTonBingReqMsg.Builder reqMsg = ChannelTonBingProto.ChannelTonBingReqMsg.newBuilder();
        reqMsg.setActivityId(config.getActivityInfo().getActivityId());
        for (int channelId : channelIdList) {
            for (long serverId : config.getActivityInfo().getServerIdList()) {
                if (ChannelActivityUnionMgr.isServerIdInChannel(serverId, channelId)) {
                    sendChannelPacket(GameProtocol.S_CTON_BING_SYNC_USER_DATA, reqMsg, serverId, channelId);
                }
            }
        }
    }
    // ============================== 缓存数据 ==============================

    // 聊天
    private ChannelTonBingChatLogic chatLogic;

    // 榜单
    private ChannelTonBingRankListModel userRank = new ChannelTonBingRankListModel(); // 个人榜
    private Map<Integer, ChannelTonBingRankListModel> campUserRankMap = new ConcurrentHashMap(); // 阵营内个人榜
    private Map<Integer, ChannelTonBingRankListModel> campUnionRankMap = new ConcurrentHashMap<>(); // 阵营内商会榜

    // 城主职位
    private Map<Long, List<ChannelTonBingUserData>> needSyncPosUserData = new ConcurrentHashMap<>();

    // ============================== 构造方法 ==============================

    public ChannelTonBingActivity(ActivityInfo activityInfo) {
        super(activityInfo);
        int nowTurn = config.getTurn();
        // 【读取数据】

        channelTonBingDataMain = ChannelTonBingActivityBusiness.getChannelTonBingDataMain(activityInfo.getActivityId());
        if (channelTonBingDataMain == null) {
            channelTonBingDataMain = new ChannelTonBingDataMain();
            channelTonBingDataMain.setActivityId(activityInfo.getActivityId());
            channelTonBingDataMain.setLockUnion(false);
            channelTonBingDataMain.setInsertOption();
        }
        userDataMap = ChannelTonBingActivityBusiness.getChannelTonBingUserDataMap(activityInfo.getActivityId());
        campDataMap = ChannelTonBingActivityBusiness.getChannelTonBingCampDataMap(activityInfo.getActivityId());
        unionJoinMap = ChannelTonBingActivityBusiness.getChannelTonBingUnionJoinMap(activityInfo.getActivityId());
        matchId = new AtomicInteger(ChannelTonBingActivityBusiness.getMaxMatchId(activityInfo.getActivityId()));

        //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑本类↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
        Map<Integer, List<ChannelTonBingCityWarReport>> cityWarReportMap =
                ChannelTonBingActivityBusiness.getCityReportListMap(activityInfo.getActivityId());
        Map<Integer, List<ChannelTonBingUserWarReport>> userWarReportsMap =
                ChannelTonBingActivityBusiness.getUserReportListMap(activityInfo.getActivityId());
        Map<Integer, Map<Integer, ChannelTonBingCampMatchData>> campMatchDataMap =
                ChannelTonBingActivityBusiness.getChannelTonBingCampMatchDataMap(activityInfo.getActivityId());

        Map<Integer, ChannelTonBingData> channelTonBingDataMap = ChannelTonBingActivityBusiness.getChannelTonBingDataMap(activityInfo.getActivityId());
        for (ChannelTonBingData channelTonBingData : channelTonBingDataMap.values()) {
            ChannelTonBingMatch match = new ChannelTonBingMatch(config, channelTonBingData);
            List<ChannelTonBingCityWarReport> cityWarReportList = cityWarReportMap.getOrDefault(channelTonBingData.getMatchId(), new ArrayList<>());
            List<ChannelTonBingUserWarReport> userWarReportsList = userWarReportsMap.getOrDefault(channelTonBingData.getMatchId(), new ArrayList<>());
            Map<Integer, ChannelTonBingCampMatchData> campDataMap = campMatchDataMap.getOrDefault(channelTonBingData.getMatchId(), new ConcurrentHashMap<>());
            Map<String, ChannelTonBingUnionJoin> joinMap = new ConcurrentHashMap<>();
            Map<Long, ChannelTonBingUserData> userDataMap = new ConcurrentHashMap<>();
            for (String unionId : channelTonBingData.getUnionIdList()) {
                joinMap.put(unionId, unionJoinMap.get(unionId));
                for (long userId : unionJoinMap.get(unionId).getMemberMap().keySet()) {
                    ChannelTonBingUserData userData = getUserData(userId);
                    if (userData != null) {
                        userDataMap.put(userId, userData);
                    }
                }
            }
            match.initData(cityWarReportList, userWarReportsList, campDataMap, joinMap, userDataMap);
            match.initAllRankList();
            if (!turnMatchMap.containsKey(channelTonBingData.getTurn())) {
                turnMatchMap.put(channelTonBingData.getTurn(), new ConcurrentHashMap<>());
            }
            if (!turnMatchMap.get(channelTonBingData.getTurn()).containsKey(channelTonBingData.getWarType())) {
                turnMatchMap.get(channelTonBingData.getTurn()).put(channelTonBingData.getWarType(), new ConcurrentHashMap<>());
            }
            turnMatchMap.get(channelTonBingData.getTurn()).get(channelTonBingData.getWarType()).put(channelTonBingData.getMatchId(), match);
            matchMap.put(channelTonBingData.getMatchId(), match);
            if (channelTonBingData.getTurn() == nowTurn) {
                //玩家有资格就会一直比赛，每一轮都有他，当前的轮次才是现在的比赛
                for (long userId : userDataMap.keySet()) {
                    userMatchMap.put(userId, match);
                }
                match.start();
            }
        }


        // 【其他初始化】
        initUserRedPacketNumMap(); // 初始化红包发送数量
        initNeedSyncPositionUser();
        chatLogic = new ChannelTonBingChatLogic(activityInfo);
        initAllRankList();

        // 启动线程
        initTask();
        thread.start();
    }


    // ============================== 数据生成获取 ==============================

    private void initUserData(long userId, int channelId, long serverId) {
        // 生成userData
        if (!userDataMap.containsKey(userId)) {
            synchronized (lock) {
                if (!userDataMap.containsKey(userId)) {
                    ChannelTonBingUserData userData = ChannelTonBingUserData.initChannelTonBingUserData(config.getActivityInfo().getActivityId(), userId);
                    userData.setChannelId(channelId);
                    userData.setServerId(serverId);
                    // 初始化兵营部分数据
                    ChannelTonBingBarracks barracks = userData.getBarracks();
                    barracks.setHospitalSize(config.getWoundedSoldierMaxNum());
                    barracks.setRescueSpeed(config.getWoundedRescueTime());
                    barracks.setRescueCount(config.getWoundedRescueCount());
                    userData.setUpdateOption();

                    // 加到map
                    userDataMap.put(userId, userData);
                }
            }
        }
    }

    /**
     * 初始化需要同步的会获得银两的职位的玩家
     */
    private void initNeedSyncPositionUser() {
        Map<Integer, Map<Integer, ChannelTonBingTitleConfig>> titleConfigMap = config.getTitleConfigMap();
        for (ChannelTonBingUserData userData : userDataMap.values()) {
            Map<Integer, Integer> posMap = userData.getPositionMap();
            if (posMap.size() != 0) {
                addNeedSyncPosUser(userData);
            }
        }
    }


    public void calcAllBarracks() {
        for (ChannelTonBingMatch match : matchMap.values()) {
            if (!match.isGameOver()) {
                match.calcAllBarracks();
            }
        }
    }

    //添加任命完的人的
    private void addNeedSyncPosUser(ChannelTonBingUserData userData) {
        synchronized (lock) {
            UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userData.getUserId());
            if (userBaseInfo != null) {
                if (!needSyncPosUserData.containsKey(userBaseInfo.getServerId())) {
                    needSyncPosUserData.put(userBaseInfo.getServerId(), new ArrayList<>());
                }
                needSyncPosUserData.get(userBaseInfo.getServerId()).add(userData);
            }
        }
    }

    private Map<Long, List<ChannelTonBingUserData>> getNeedSyncPosUserDataMap() {
        synchronized (lock) {
            if (needSyncPosUserData.size() == 0) {
                Map<Long, List<ChannelTonBingUserData>> tempMap = new ConcurrentHashMap<>();
                Map<Integer, Map<Integer, ChannelTonBingTitleConfig>> titleConfigMap = config.getTitleConfigMap();
                for (ChannelTonBingUserData userData : userDataMap.values()) {
                    Map<Integer, Integer> posMap = userData.getPositionMap();
                    for (int posType : posMap.keySet()) {
                        if (posMap.get(posType) != eTonBingPosition.None.getValue()) {
                            ChannelTonBingTitleConfig titleConfig = titleConfigMap.get(userData.getCampId()).get(posMap.get(posType));
                            if (titleConfig.getType() == 1) {
                                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userData.getUserId());
                                if (userBaseInfo != null) {
                                    if (!tempMap.containsKey(userBaseInfo.getServerId())) {
                                        tempMap.put(userBaseInfo.getServerId(), new ArrayList<>());
                                    }
                                    if (!tempMap.get(userBaseInfo.getServerId()).contains(userData)) {
                                        tempMap.get(userBaseInfo.getServerId()).add(userData);
                                    }
                                }
                            }
                        }
                    }

                }
                needSyncPosUserData = tempMap;
            }
            return needSyncPosUserData;
        }
    }

    //同步玩家身上的数据
    public void syncUserData(long userId, ChannelTonBingProto.CTonBingUserDataSyncMsg reqMsg) {
        ChannelTonBingUserData userData = getUserData(userId);
        if (userData == null) {
            return;
        }
        ChannelTonBingProto.CTonBingUserDataSyncMsg.Builder respMsg = reqMsg.toBuilder();
        ChannelTonBingMatch match = getMatchByUserId(userId);
        //这个版本这个东西没用了，客户端不知道怎么判断了
        respMsg.setWinnerId(0);
        if (match != null) {
            respMsg.setMatchId(match.getChannelTonBingData().getMatchId());
            respMsg.setWarType(match.getChannelTonBingData().getWarType());
        }

        sendChannelPacket(ClientProtocol.U_CTON_BING_USER_DATA_SYNC, respMsg, userData);
    }

    /**
     * 添加红点
     */
    private void addRedDot(ChannelTonBingUserData userData, eTonBingRedDotType type) {

        if (userData.getRedDotMap().containsKey(type.getValue())) {
            return;
        }
        userData.getRedDotMap().put(type.getValue(), System.currentTimeMillis());
        userData.setUpdateOption();

        ChannelTonBingProto.CTonBingSyncRedDotRespMsg.Builder builder = ChannelTonBingProto.CTonBingSyncRedDotRespMsg.newBuilder();
        builder.addType(type.getValue());
        sendChannelPacket(ClientProtocol.U_CTON_BING_SYNC_RED_DOT, builder, userData);
    }

    private ChannelTonBingRedPacket oneRedPacket(int campId, long userId, int goodId) {
        ChannelTonBingCampData campData = campDataMap.get(campId);
        Map<Long, ChannelTonBingRedPacket> redPacketMap = campData.getRedPacketMap();

        ChannelTonBingRedPacket redPacket;
        synchronized (lock) {
            // 生成红包
            redPacket = new ChannelTonBingRedPacket();
            redPacket.setUserId(userId);
            redPacket.setGoodId(goodId);
            redPacket.setTime(System.currentTimeMillis());
            redPacket.setRedPacketNo(redPacketMap.size() + 1);
            // 加map
            redPacketMap.put(redPacket.getRedPacketNo(), redPacket);
            campData.setUpdateOption();
            // 加统计数量
            addUserRedPacketCount(redPacket, campData);
        }

        return redPacket;
    }

    /**
     * 使用道具后给阵营加红包
     */
    public void addRedPacket(long userId, ChannelTonBingProto.ChannelTonBingRedPacketAddReqMsg reqMsg) {
        ChannelTonBingUserData userData = getUserData(userId);
        if (userData == null) {
            return;
        }
        if (!isAble(userData)) {
            logger.error("ton bing addRedPacket fail, no able! activityId {}, userId {}.", config.getActivityInfo().getActivityId(), userId);
            return;
        }

        int campId = userData.getCampId();
        ChannelTonBingCampData campData = campDataMap.get(campId);
        if (campData == null) {
            logger.error("ton bing addRedPacket fail, no camp data! activityId {}, userId {}.", config.getActivityInfo().getActivityId(), userId);
            return;
        }

        List<ChannelTonBingRedPacket> redPacketSyncList = new ArrayList<>();
        synchronized (lock) {
            for (int i = 0; i < reqMsg.getNum(); i++) {
                redPacketSyncList.add(oneRedPacket(campId, userId, reqMsg.getGoodId()));
            }
        }

        if (redPacketSyncList.size() > 0) {
            syncRedPacketToCampUser(userId, redPacketSyncList);

            // 红点
            for (ChannelTonBingUserData tmpUserData : userDataMap.values()) {
                if (tmpUserData.getCampId() == campId) {
                    addRedDot(tmpUserData, eTonBingRedDotType.Type9_GetBox);
                }
            }
        }
    }

    // 买完宝箱礼包，同步所有阵营玩家有礼包了
    public void syncRedPacketToCampUser(long userId, List<ChannelTonBingRedPacket> redPacketSyncList) {
        ChannelTonBingUserData rpUserData = getUserData(userId);
        UserBaseInfo rpUserBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
        if (rpUserBaseInfo == null) {
            return;
        }
        ChannelTonBingProto.ChannelTonBingRedPacketSyncMsg.Builder syncMsg = ChannelTonBingProto.ChannelTonBingRedPacketSyncMsg.newBuilder();
        for (ChannelTonBingRedPacket redPacket : redPacketSyncList) {
            ChannelTonBingProto.CTonBingRedPacketMsg.Builder redPacketMsg = ChannelTonBingProto.CTonBingRedPacketMsg.newBuilder();
            redPacketMsg.setUserId(userId);
            redPacketMsg.setNickName(rpUserBaseInfo.getNickName());
            redPacketMsg.setUnionName(rpUserBaseInfo.getUnionName());
            redPacketMsg.setType(redPacket.getGoodId());
            redPacketMsg.setIsGet(0);
            redPacketMsg.setOrderNo("" + redPacket.getRedPacketNo());
            syncMsg.addRedPackets(redPacketMsg);
        }
        List<Long> serverIdList = new ArrayList<>();
        for (ChannelTonBingUserData userData : userDataMap.values()) {
            if (userData.getCampId() == rpUserData.getCampId()) {
                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userData.getUserId());
                if (userBaseInfo != null) {
                    syncMsg.addUserIds(userData.getUserId());
                    if (!serverIdList.contains(userBaseInfo.getServerId())) {
                        serverIdList.add(userBaseInfo.getServerId());
                    }
                }
            }
        }
        for (long serverId : serverIdList) {
            //客户端说不用了
        }
    }

    public int getChannelIdByCampId(ChannelTonBingCampData campData) {
        if (campData == null) {
            return 0;
        }

        int channelId = 0;
        for (ChannelTonBingRedPacket redPacket : campData.getRedPacketMap().values()) {
            ChannelTonBingUserData userData = getUserData(redPacket.getUserId());
            if (userData == null) {
                continue;
            }
            channelId = userData.getChannelId();
            break;
        }
        return channelId;
    }

    //同步宝箱值去本服改condition
    public void syncRedPacketBoxValue() {
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        for (ChannelTonBingCampData campData : new ConcurrentHashMap<>(campDataMap).values()) {
            if (campData.getRedPacketValue() > 0 && campData.getCampId() != 0) {
                Map<Long, List<Long>> serverUserMap = getCampServerIdUserIdMap(campData.getCampId());

                int channelId = getChannelIdByCampId(campData);
                if (channelId == 0) {
                    continue;
                }

                ChannelTonBingProto.ChannelTonBingRedPacketBoxValueSyncMsg.Builder syncMsg = ChannelTonBingProto.ChannelTonBingRedPacketBoxValueSyncMsg.newBuilder();
                syncMsg.setActivityId(campData.getActivityId());
                syncMsg.setValue(campData.getRedPacketValue());
                ChannelMessageHelper.sendGamePacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_BOX_VALUE_SYNC, syncMsg, channelId, serverUserMap);
            }
        }
    }

    private Map<Long, List<Long>> getCampServerIdUserIdMap(int campId) {
        Map<Long, List<Long>> resMap = new ConcurrentHashMap<>();
        for (ChannelTonBingUserData userData : new ConcurrentHashMap<>(userDataMap).values()) {
            if (userData.getCampId() == campId) {
                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userData.getUserId());
                if (userBaseInfo != null) {
                    if (!resMap.containsKey(userBaseInfo.getServerId())) {
                        resMap.put(userBaseInfo.getServerId(), new ArrayList<>());
                    }
                    resMap.get(userBaseInfo.getServerId()).add(userData.getUserId());
                }
            }
        }
        return resMap;
    }

    // 新增玩家的红包宝箱信息
    public void addUserRedPacketCount(ChannelTonBingRedPacket redPacket, ChannelTonBingCampData campData) {
        Map<Long, ChannelTonBingUserRedPacketCount> userRedPacketMap = campData.getUserRedPacketMap();
        if (!userRedPacketMap.containsKey(redPacket.getUserId())) {
            ChannelTonBingUserRedPacketCount temp = new ChannelTonBingUserRedPacketCount();
            temp.setUserId(redPacket.getUserId());
            userRedPacketMap.put(redPacket.getUserId(), temp);
        }
        ChannelTonBingUserRedPacketCount userRedPacket = userRedPacketMap.get(redPacket.getUserId());
        Map<Integer, Integer> redPacketCountMap = userRedPacket.getUserRedPacketCountMap();
        redPacketCountMap.put(redPacket.getGoodId(), redPacketCountMap.getOrDefault(redPacket.getGoodId(), 0) + 1);
        userRedPacket.setUserRedPacketCountMap(redPacketCountMap);
    }

    /**
     * 获取红包列表（优先没领取的）
     */
    public void getRedPacketList(long userId) {
        ChannelTonBingProto.CTonBingRedPacketGetListRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingRedPacketGetListRespMsg.newBuilder();
        respMsg.setRet(0);

        ChannelTonBingUserData userData = getUserData(userId);
        int campId = userData.getCampId();

        // 没资格
        if (!isAble(userData)) {
            respMsg.setRet(GameErrorCode.E_TON_BING_NO_ABLE);
            sendChannelPacket(ClientProtocol.U_CTON_BING_RED_PACKET_LIST, respMsg, userData);
            return;
        }

        // 统计红包
        LinkedList<ChannelTonBingRedPacket> noGetRewardList = new LinkedList<>();
        LinkedList<ChannelTonBingRedPacket> getRewardList = new LinkedList<>();
        ChannelTonBingCampData campData = campDataMap.get(campId);
        if (campData != null) {
            for (ChannelTonBingRedPacket redPacket : campData.getRedPacketMap().values()) {
                if (redPacket.getGetRewardUserList().contains(userId)) {
                    getRewardList.add(redPacket);
                } else {
                    noGetRewardList.add(redPacket);
                }
            }
        }

        // 发送晚的在前
        noGetRewardList.sort(new RedPacketSort());
        getRewardList.sort(new RedPacketSort());

        // 拿前50个
        int maxNum = 50;
        int num = 1;
        for (ChannelTonBingRedPacket redPacket : noGetRewardList) {
            if (num >= maxNum) {
                break;
            }
            respMsg.addRedPackets(parseTonBingRedPacketMsg(redPacket, false));
            num++;
        }
        for (ChannelTonBingRedPacket redPacket : getRewardList) {
            if (num >= maxNum) {
                break;
            }
            respMsg.addRedPackets(parseTonBingRedPacketMsg(redPacket, true));
            num++;
        }

        sendChannelPacket(ClientProtocol.U_CTON_BING_RED_PACKET_LIST, respMsg, userData);
    }

    public void getBattleInfo(long userId, int channelId, long serverId) {
        checkPatrons(userId);
        ChannelTonBingProto.CTonBingGetBattleInfoRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingGetBattleInfoRespMsg.newBuilder();
        int turn = config.getTurn();
        long nowTime = System.currentTimeMillis();
        if (nowTime > config.getActivityInfo().getEndTime() * 1000) {
            turn = config.getLastTurn();
        }
        List<Integer> warTypeList = config.getWarTypeList();
        Map<Integer, Map<Integer, ChannelTonBingMatch>> turnMap = turnMatchMap.get(turn);
        for (int warType : warTypeList) {
            ChannelTonBingProto.CTonBingBattleInfoTempMsg.Builder tmpMsg = ChannelTonBingProto.CTonBingBattleInfoTempMsg.newBuilder();
            tmpMsg.setWarType(warType);
            tmpMsg.setUnionCount(0);
            if (turnMap != null && turnMap.containsKey(warType)) {
                int unionCount = 0;
                for (ChannelTonBingMatch match : turnMap.get(warType).values()) {
                    tmpMsg.addMatchId(match.getChannelTonBingData().getMatchId());
                    unionCount += match.getUnionJoinMap().size();
                }
                tmpMsg.setUnionCount(unionCount);
            }
            respMsg.addInfo(tmpMsg);
        }
        ChannelTonBingUserData userData = getUserData(userId);
        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_BATTLE_INFO, respMsg, channelId, serverId, userId);
    }

    public void getTodayRankInfo(long userId, int chanelId, long serverId) {
        ChannelTonBingProto.CTonBingGetTodayRankRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingGetTodayRankRespMsg.newBuilder();
        respMsg.setRet(0);
        int nowTurn = config.getTurn();
        long nowTime = System.currentTimeMillis();
        if (nowTime > config.getActivityInfo().getEndTime() * 1000) {
            nowTurn = config.getLastTurn();
        }
        for (ChannelTonBingMatch match : matchMap.values()) {
            if (match.getChannelTonBingData().getTurn() != nowTurn) continue;
            respMsg.addList(match.getCampUnionRankToday(userId));
        }
        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_TODAY_RANK, respMsg, chanelId, serverId, userId);
    }

    class RedPacketSort implements Comparator<ChannelTonBingRedPacket> {
        @Override
        public int compare(ChannelTonBingRedPacket o1, ChannelTonBingRedPacket o2) {
            return Long.compare(o2.getTime(), o1.getTime());
        }
    }

    /**
     * 初始化各阵营红包排行
     */
    public void initUserRedPacketNumMap() {
        for (ChannelTonBingCampData campData : campDataMap.values()) {
            Map<Long, ChannelTonBingUserRedPacketCount> tempMap = new ConcurrentHashMap<>();
            for (ChannelTonBingRedPacket redPacket : campData.getRedPacketMap().values()) {
                if (!tempMap.containsKey(redPacket.getUserId())) {
                    ChannelTonBingUserRedPacketCount temp = new ChannelTonBingUserRedPacketCount();
                    temp.setUserId(redPacket.getUserId());
                    tempMap.put(redPacket.getUserId(), temp);
                }
                ChannelTonBingUserRedPacketCount userRedPacketCount = tempMap.get(redPacket.getUserId());
                Map<Integer, Integer> redPacketCountMap = userRedPacketCount.getUserRedPacketCountMap();
                redPacketCountMap.put(redPacket.getGoodId(), redPacketCountMap.getOrDefault(redPacket.getGoodId(), 0) + 1);
                userRedPacketCount.setUserRedPacketCountMap(redPacketCountMap);
            }
            campData.setUserRedPacketMap(tempMap);
        }
    }


    /**
     * 红包发送记录
     */
    public void getRedPacketRecord(long userId) {
        ChannelTonBingProto.CTonBingRedPacketGetRecordRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingRedPacketGetRecordRespMsg.newBuilder();
        respMsg.setRet(0);

        ChannelTonBingUserData userData = getUserData(userId);
        if (!isAble(userData)) {
            respMsg.setRet(GameErrorCode.E_TON_BING_NO_ABLE);
            sendChannelPacket(ClientProtocol.U_CTON_BING_RED_PACKET_RECORD_LIST, respMsg, userData);
            return;
        }

        ChannelTonBingCampData campData = campDataMap.get(userData.getCampId());
        if (campData != null) {
            Map<Long, ChannelTonBingUserRedPacketCount> userRedPacketMap = campData.getUserRedPacketMap();
            for (ChannelTonBingUserRedPacketCount userRedPacket : userRedPacketMap.values()) {
                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userRedPacket.getUserId());
                if (userBaseInfo == null) {
                    userBaseInfo = new UserBaseInfo();
                }

                ChannelTonBingProto.CTonBingRedPacketRankMsg.Builder rankTempMsg = ChannelTonBingProto.CTonBingRedPacketRankMsg.newBuilder();
                rankTempMsg.setUserId(userRedPacket.getUserId());
                rankTempMsg.setNickName(userBaseInfo.getNickName());
                for (Map.Entry<Integer, Integer> entry : userRedPacket.getUserRedPacketCountMap().entrySet()) {
                    ChannelTonBingProto.CTonBingRedPacketBoxMsg.Builder boxTempMsg = ChannelTonBingProto.CTonBingRedPacketBoxMsg.newBuilder();
                    boxTempMsg.setBoxKey(entry.getKey());
                    boxTempMsg.setNum(entry.getValue());
                    rankTempMsg.addBox(boxTempMsg);
                }
                respMsg.addRecords(rankTempMsg);
            }
        }

        sendChannelPacket(ClientProtocol.U_CTON_BING_RED_PACKET_RECORD_LIST, respMsg, userData);
    }


    /**
     * 领取阵营宝箱
     */
    public void getRedPacketBox(long userId, ChannelTonBingProto.ChannelTonBingRedPacketGetBoxReqMsg reqMsg) {
        ChannelTonBingProto.ChannelTonBingRedPacketGetBoxRespMsg.Builder serverMsg = ChannelTonBingProto.ChannelTonBingRedPacketGetBoxRespMsg.newBuilder();
        serverMsg.setRet(0);

        // 资格
        ChannelTonBingUserData userData = getUserData(userId);
        if (!isAble(userData)) {
            serverMsg.setRet(GameErrorCode.E_TON_BING_NO_ABLE);
            sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
            return;
        }

        // 数据判断
        ChannelTonBingCampData campData = campDataMap.get(userData.getCampId());
        if (campData == null) {
            serverMsg.setRet(GameErrorCode.E_TON_BING_RED_PACKET_IS_GET);
            sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
            return;
        }

        long boxNo = StringUtils.isNullOrEmpty(reqMsg.getOrderNo()) ? 0 : Long.valueOf(reqMsg.getOrderNo());
        Map<Integer, ChannelTonBingCampBoxConfig> campBoxConfigMap = config.getCampBoxConfigMap();
        Map<Long, ChannelTonBingRedPacket> redPacketMap = campData.getRedPacketMap();

        synchronized (lock) {

            if (boxNo == 0) {
                // 【一键领取】
                Property reward = new Property();
                for (ChannelTonBingRedPacket redPacket : redPacketMap.values()) {
                    Set<Long> getRewardUserList = redPacket.getGetRewardUserList();
                    if (!getRewardUserList.contains(userId)) {
                        ChannelTonBingCampBoxConfig campBoxConfig = campBoxConfigMap.get(redPacket.getGoodId());
                        reward.addProperty(campBoxConfig.getBoxId(), BigInteger.ONE);
                        getRewardUserList.add(userId);
                        campData.setRedPacketValue(campData.getRedPacketValue() + campBoxConfig.getBoxScore());
                    }
                }
                String rewardStr = PropertyHelper.parsePropertyToString(reward);
                if (StringUtils.isNullOrEmpty(rewardStr)) {
                    serverMsg.setRet(GameErrorCode.E_TON_BING_RED_PACKET_IS_GET);
                    sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
                    return;
                }
                serverMsg.setReward(rewardStr);
                sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
                campData.setUpdateOption();
            } else {
                // 【单个领取】
                ChannelTonBingRedPacket redPacket = redPacketMap.get(boxNo);
                if (redPacket == null) {
                    serverMsg.setRet(GameErrorCode.E_TON_BING_RED_PACKET_NO_EXIT);
                    sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
                    return;
                }
                Set<Long> getRewardList = redPacket.getGetRewardUserList();
                if (getRewardList.contains(userId)) {
                    serverMsg.setRet(GameErrorCode.E_TON_BING_RED_PACKET_IS_GET);
                    sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
                    return;
                }
                ChannelTonBingCampBoxConfig campBoxConfig = campBoxConfigMap.get(redPacket.getGoodId());
                getRewardList.add(userId);
                campData.setRedPacketValue(campData.getRedPacketValue() + campBoxConfig.getBoxScore());
                serverMsg.setReward(campBoxConfig.getBoxId() + "=1");
                // 一键领取的时候还要下去连大宝箱都领了
                serverMsg.setBoxValue(campData.getRedPacketValue());
                serverMsg.setActivityId(config.getActivityInfo().getActivityId());
                sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_RED_PACKET_GET_BOX, serverMsg, userData);
                campData.setUpdateOption();
            }
        }
    }

    /**
     * 锁定名单时有资格的才会有userdata
     *
     * @param userId
     * @return
     */
    public ChannelTonBingUserData getUserData(long userId) {
        ChannelTonBingUserData userData = userDataMap.get(userId);
        return userData;
    }

    public ChannelTonBingUnionJoin getUnionJoin(String unionUid) {
        return unionJoinMap.get(unionUid);
    }

    public ChannelTonBingDataMain getChannelTonBingDataMain() {
        return channelTonBingDataMain;
    }

    // ============================== 定时器 ==============================

    /**
     * 初始化所有Task
     */
    public void initTask() {

        // 商会报名锁定
        long checkLockTime = Math.min(System.currentTimeMillis(), config.getJoinTimeList().get(1) + DateHelper.MINUTE_MILLIONS); // 锁名单前，要检查下其他数据
        addTask(new ChannelTonBingLockUnionTask(this, checkLockTime));
        long makeMatchStartTime = Math.min(System.currentTimeMillis(), config.getJoinTimeList().get(1) + 10000); // 开始生成比赛时间
        addTask(new ChannelTonBingMakeMatchTask(this, makeMatchStartTime));

        addTask(new ChannelTonBingSetWinnerTask(this, config.getActivityInfo().getEndTime() * 1000L));
    }

    //锁定玩排行榜设置商会信息
    public void lockUnionMsg(RankProto.CrossUnionRankListLockMsg lockMsg) {

        List<Long> syncList = new ArrayList<>();

        synchronized (lock) {

            // 时间
            boolean lockUnion = getChannelTonBingDataMain().isLockUnion();
            boolean activityEnd = System.currentTimeMillis() > config.getActivityInfo().getEndTime() * 1000L;

            // 结束了就无法操作了
            if (activityEnd) {
                return;
            }

            // 自动报名数据（这里还是按赚速，拿不到最高赚钱）
            List<RankProto.CrossUnionRankLockTemp> rankList = lockMsg.getRankList();

            // 遍历数据一个个处理
            int i = 0;//加入计数
            for (RankProto.CrossUnionRankLockTemp unionMsg : rankList) {
                if (i < config.getUnionNum()) {
                    // 【商会处理】
                    ChannelTonBingUnionJoin join = unionJoinMap.get(unionMsg.getRankTemp().getUnionUid());
                    if (join == null) {
                        if (!lockUnion) {
                            join = new ChannelTonBingUnionJoin();
                            join.setActivityId(config.getActivityInfo().getActivityId());
                            join.setUnionUid(unionMsg.getRankTemp().getUnionUid());
                            join.setUnionBaseInfo(UnionBasePb.parseUnionBaseInfo(unionMsg.getRankTemp().getUnionBaseData()));
                            join.setMemberMap(new ConcurrentHashMap<>());
                            //已经拉过来是多少就是多少了，不用再去本服更新来更新去了，这个已经是历史最高赚钱了
                            join.setTotalAbility(Long.valueOf(unionMsg.getRankTemp().getValue()));
                            join.setInsertOption();
                            unionJoinMap.put(join.getUnionUid(), join);
                        }
                    }
                    if (join == null) {
                        continue;
                    }

                    // 【成员处理】
                    Map<Long, ChannelTonBingUnionJoinMember> oldMap = join.getMemberMap();
                    if (!lockUnion) {
                        Map<Long, ChannelTonBingUnionJoinMember> memberMap = new ConcurrentHashMap<>();
                        for (RankProto.CrossUnionMemberTemp msg : unionMsg.getMemberList()) {
                            ChannelTonBingUnionJoinMember member = oldMap.remove(msg.getMemberId());
                            if (member == null) {
                                member = new ChannelTonBingUnionJoinMember(msg.getMemberId(), msg.getServerId(), msg.getChannelId());
                                syncList.add(member.getUserId()); // 添加报名状态同步
                            }
                            member.setPosition(msg.getPosition());
                            member.setServerId(msg.getServerId());
                            member.setChannelId(msg.getChannelId());
                            memberMap.put(member.getUserId(), member);
                        }
                        join.setMemberMap(memberMap);
                        syncList.addAll(oldMap.keySet()); // 添加报名状态同步
                    } else {
                        for (RankProto.CrossUnionMemberTemp msg : unionMsg.getMemberList()) {
                            ChannelTonBingUnionJoinMember member = oldMap.get(msg.getMemberId());
                            if (member != null) {
                                member.setPosition(msg.getPosition());
                                member.setServerId(msg.getServerId());
                                member.setChannelId(msg.getChannelId());
                            }
                        }
                    }
                    join.setUpdateOption();
                }
                // 日志
                ChannelAutoLogMgr.add(new LogChannelTonBingJoin(
                        config.getActivityInfo().getActivityId(),
                        -1,
                        unionMsg.getRankTemp().getUnionUid(),
                        i < config.getUnionNum() ? 1 : 0,
                        unionMsg.getRankTemp().getValue()
                ));
                i++;
            }
        }

        // 同步报名状态
        for (Long userId : syncList) {
            syncBaseDataMsg(getUserData(userId));
        }
    }

    public void lockUnionChannelMsg(Map<Integer, LinkedList<ActivityUnionInfo>> channelUnionMap) {

        List<Long> syncList = new ArrayList<>();

        synchronized (lock) {

            // 时间
            boolean lockUnion = getChannelTonBingDataMain().isLockUnion();
            boolean activityEnd = System.currentTimeMillis() > config.getActivityInfo().getEndTime() * 1000L;

            // 结束了就无法操作了
            if (activityEnd) {
                return;
            }
            // 遍历数据一个个处理
            for (int channelId : channelUnionMap.keySet()) {
                LinkedList<ActivityUnionInfo> unionList = channelUnionMap.get(channelId);
                int i = 0;//加入计数
                for (ActivityUnionInfo unionInfo : unionList) {
                    if (i < config.getUnionChannelNum()) {
                        // 【商会处理】
                        ChannelTonBingUnionJoin join = unionJoinMap.get(unionInfo.getUnionId());
                        if (join == null) {
                            if (!lockUnion) {
                                join = new ChannelTonBingUnionJoin();
                                join.setActivityId(config.getActivityInfo().getActivityId());
                                join.setUnionUid(unionInfo.getUnionId());
                                join.setUnionBaseInfo(unionInfo.getUnionBaseInfo());
                                join.setMemberMap(new ConcurrentHashMap<>());
                                //已经拉过来是多少就是多少了，不用再去本服更新来更新去了，这个已经是历史最高赚钱了
                                join.setTotalAbility(unionInfo.getTotalAbility().longValue());
                                join.setInsertOption();
                                unionJoinMap.put(join.getUnionUid(), join);
                            }
                        }
                        if (join == null) {
                            continue;
                        }

                        // 【成员处理】
                        Map<Long, ChannelTonBingUnionJoinMember> oldMap = join.getMemberMap();
                        if (!lockUnion) {
                            Map<Long, ChannelTonBingUnionJoinMember> memberMap = new ConcurrentHashMap<>();
                            for (ActivityUnionMemberInfo msg : unionInfo.getMemberInfoMap().values()) {
                                initUserData(msg.getUserId(), msg.getChannelId(), msg.getServerId());
                                ChannelTonBingUnionJoinMember member = oldMap.remove(msg.getUserId());
                                if (member == null) {
                                    member = new ChannelTonBingUnionJoinMember(msg.getUserId(), msg.getServerId(), msg.getChannelId());
                                    syncList.add(member.getUserId()); // 添加报名状态同步
                                }
                                member.setPosition(msg.getPosition());
                                member.setServerId(msg.getServerId());
                                member.setChannelId(msg.getChannelId());
                                memberMap.put(member.getUserId(), member);
                            }
                            join.setMemberMap(memberMap);
                            syncList.addAll(oldMap.keySet()); // 添加报名状态同步
                        } else {
                            for (ActivityUnionMemberInfo msg : unionInfo.getMemberInfoMap().values()) {
                                ChannelTonBingUnionJoinMember member = oldMap.get(msg.getUserId());
                                if (member != null) {
                                    member.setPosition(msg.getPosition());
                                    member.setServerId(msg.getServerId());
                                    member.setChannelId(msg.getChannelId());
                                }
                            }
                        }
                        join.setUpdateOption();
                    }
                    // 日志
                    ChannelAutoLogMgr.add(new LogChannelTonBingJoin(
                            config.getActivityInfo().getActivityId(),
                            -1,
                            unionInfo.getUnionId(),
                            i < config.getUnionChannelNum() ? 1 : 0,
                            unionInfo.getTotalAbility().toString()
                    ));
                    i++;
                }
            }
        }

        // 同步报名状态
        for (Long userId : syncList) {
            syncBaseDataMsg(getUserData(userId));
        }

        //去跨服统一拉有资格玩家的userBaseInfo
        for (int channelId : channelIdList) {
            ChannelTonBingProto.CTonBingGoGetUserBaseInfoReqMsg.Builder reqMsg = ChannelTonBingProto.CTonBingGoGetUserBaseInfoReqMsg.newBuilder();
            reqMsg.setActivityId(config.getActivityInfo().getActivityId());
            reqMsg.addAllUserId(syncList);
            YanQuMessage message = YanQuMessageUtils.buildMessage(Cross3Protocol.C3_CROSS_QUERY_USER_BASE_INFO, reqMsg);
            ChannelMessageHelper.sendToChannel(message, channelId);
        }
    }

    /**
     * 商会报名、锁名单 任务
     */
    public void channelTonBingLockUnionTask() {
        // 【已经锁名单了】
        if (getChannelTonBingDataMain().isLockUnion()) {
            return;
        }

        long now = System.currentTimeMillis();

        // 报名期结束 锁定商会名单
        if (now > config.getJoinTimeList().get(1) + DateHelper.MINUTE_MILLIONS) {
            logger.error("活动{}巅峰统兵准备榜单锁定", config.getActivityInfo().getActivityId());
            /*List<Long> serverList = config.getActivityInfo().getServerIdList();
            int index = randomHelper.next(0,serverList.size());
            long serverId = serverList.get(index);
            //报名期结算就去拉取有资格的商会
            MessageHelper.sendChannelPacket(serverId, 0,
                    YanQuMessageUtils.buildMessage(GameProtocol.S_PEAK_UNION_MAX_ABILITY_RANK_LOCK,
                            CommonActivityProto.CommonActivityRankListReqMsg.newBuilder().setActivityId(config.getActivityInfo().getActivityId())));*/
            ChannelActivityUnionMgr.tonBingGameStartChannel(config.getActivityInfo().getActivityId());
            //需要快速请求本服的判断两秒就算过期的
            long next10Second = System.currentTimeMillis() + DateHelper.SECOND_MILLIONS * 5;
            addTask(new ChannelTonBingLockUnionTask(this, next10Second));
        } else {
            // 【没锁名单】先把任务加回去比较稳
            long next10Second = System.currentTimeMillis() + DateHelper.SECOND_MILLIONS * 10;
            addTask(new ChannelTonBingLockUnionTask(this, next10Second));
        }
    }


    // ============================== 榜单 ==============================

    /**
     * 初始化全部榜单
     */
    private void initAllRankList() {
        ChannelTonBingRankListModel userModel = new ChannelTonBingRankListModel();
        Map<Integer, ChannelTonBingRankListModel> campUserMap = new ConcurrentHashMap<>();
        Map<Integer, ChannelTonBingRankListModel> campUnionMap = new ConcurrentHashMap<>();

        for (ChannelTonBingUserData userData : userDataMap.values()) {
            if (isAble(userData)) {
                ChannelTonBingRank rank = new ChannelTonBingRank(String.valueOf(userData.getUserId()), userData.getZhanGong(), userData.getZhanGongTime());
                // 【个人榜】
                userModel.rankChange(rank);
                // 【阵营内个人榜】
                campUserMap.putIfAbsent(userData.getCampId(), new ChannelTonBingRankListModel());
                campUserMap.get(userData.getCampId()).rankChange(rank);
            }
        }


        for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
            if (join.getCampId() != 0) {
                // 【阵营内商会榜】
                campUnionMap.putIfAbsent(join.getCampId(), new ChannelTonBingRankListModel());
                ChannelTonBingRank rank = getUnionZhanGongRank(join);
                campUnionMap.get(join.getCampId()).rankChange(rank);
            }
        }

        userRank = userModel;
        campUserRankMap = campUserMap;
        campUnionRankMap = campUnionMap;
        //asdasd商会榜才整个战场吧，提出来，乱的一比
    }

    public void rankZhanGong(long userId, long battleTime) {
        ChannelTonBingUserData userData = getUserData(userId);

        // 个人榜
        ChannelTonBingRank rank = new ChannelTonBingRank(String.valueOf(userId), userData.getZhanGong(), battleTime);
        userRank.rankChange(rank);

        // 阵营内个人榜
        campUserRankMap.putIfAbsent(userData.getCampId(), new ChannelTonBingRankListModel());
        campUserRankMap.get(userData.getCampId()).rankChange(rank);

        // 阵营内商会榜
        ChannelTonBingUnionJoin join = unionJoinMap.get(userData.getUnionUid());
        if (join != null) {
            long unionValue = 0;
            for (long memberId : join.getMemberMap().keySet()) {
                ChannelTonBingUserData memberData = getUserData(memberId);
                unionValue += memberData.getZhanGong();
            }

            ChannelTonBingRank unionRank = new ChannelTonBingRank(join.getUnionUid(), unionValue, battleTime);
            unionRank.setAbility(join.getTotalAbility());
            //商会排行榜还要战场排，其他搞不懂，先没有吧，太乱了
            unionRank.setWarType(getNowWarType(unionRank.getId()));

            campUnionRankMap.putIfAbsent(userData.getCampId(), new ChannelTonBingRankListModel());
            campUnionRankMap.get(userData.getCampId()).rankChange(unionRank);
        }
    }

    /**
     * 获取商会战功Rank
     */
    private ChannelTonBingRank getUnionZhanGongRank(ChannelTonBingUnionJoin join) {
        long unionValue = 0;
        long maxTime = 0;
        for (long memberId : join.getMemberMap().keySet()) {
            ChannelTonBingUserData memberData = getUserData(memberId);
            unionValue += memberData.getZhanGong();
            maxTime = Math.max(maxTime, memberData.getZhanGongTime());
        }

        ChannelTonBingRank rank = new ChannelTonBingRank(join.getUnionUid(), unionValue, maxTime);
        rank.setAbility(join.getTotalAbility());
        rank.setWarType(getNowWarType(join.getUnionUid()));

        return rank;
    }

    // ============================== 战斗 ==============================

    // ============================== 报名 ==============================

    /**
     * 请求商会跨服拿成员数据 todo-xx 测一下
     */
    public void sendGetUnionMsg(String unionId) {
        ChannelTonBingUnionJoin unionJoin = getUnionJoin(unionId);
        if (unionJoin == null) {
            return;
        }
        int channelId = unionJoin.getChannelId();
        long serverId = unionJoin.getServerId();

        ChannelTonBingProto.ChannelGetUnionUpdateReqMsg.Builder builder = ChannelTonBingProto.ChannelGetUnionUpdateReqMsg.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setGameServerId(serverId);
        builder.addUnionUid(unionId);

        sendChannelPacket(Cross3Protocol.C3_ACTIVITY_GET_UNION_UPDATE, builder, serverId, channelId);
    }

    public void updateUnionByCmd(ChannelTonBingProto.ChannelGetUnionUpdateRespMsg reqMsg) {
        synchronized (lock) {
            boolean activityEnd = System.currentTimeMillis() > config.getActivityInfo().getEndTime() * 1000L;
            // 结束了就无法操作了
            if (activityEnd) {
                return;
            }
            // 遍历数据一个个处理
            for (ChannelTonBingProto.CUnionMsg unionMsg : reqMsg.getUnionList()) {
                // 【商会处理】
                ChannelTonBingUnionJoin join = unionJoinMap.get(unionMsg.getUnionUid());
                if (join != null) {
                    join.setUnionBaseInfo(UnionBasePb.parseUnionBaseInfo(unionMsg.getUnionInfo()));
                } else {
                    continue;
                }
                Map<Long, ChannelTonBingUnionJoinMember> oldMap = join.getMemberMap();
                for (ChannelTonBingProto.CUnionMemberInfoMsg msg : unionMsg.getMemberList()) {
                    ChannelTonBingUnionJoinMember member = oldMap.get(msg.getUserId());
                    if (member != null) {
                        member.setPosition(msg.getPosition());
                    } else {
                        member = new ChannelTonBingUnionJoinMember(msg.getUserId(), msg.getServerId(), msg.getChannelId());
                        member.setPosition(msg.getPosition());
                        oldMap.put(member.getUserId(), member);
                    }
                }
                join.setUpdateOption();
            }
        }
    }


    /**
     * 锁定商会
     */
    public void lockUnion(RankProto.CrossUnionRankListLockMsg lockMsg) {
        synchronized (lock) {
            lockUnionMsg(lockMsg);
            if (getChannelTonBingDataMain().isLockUnion()) {
                return;
            }

            // 排序拿前几名
            List<ChannelTonBingUnionJoin> rankList = unionJoinMap.values().stream()
                    .sorted(new Comparator<ChannelTonBingUnionJoin>() {
                        @Override
                        public int compare(ChannelTonBingUnionJoin o1, ChannelTonBingUnionJoin o2) {
                            // 922 3372 0368亿
                            return Long.compare(o2.getTotalAbility(), o1.getTotalAbility());
                        }
                    })
                    .limit(config.getUnionNum())
                    .collect(Collectors.toList());

            // 分阵营
            lockCamp(rankList);

            // 改状态
            getChannelTonBingDataMain().setLockUnion(true);
            logger.error("tonbing activity {} lock union.", config.getActivityInfo().getActivityId());

            // 移动玩家到起始点 到对应的比赛中去做这件事情了
//            channelTonBingInitTeamPosTask();

            // 初始化榜单，让0值的也上榜，才能看到自己阵营都有谁
            initAllRankList();

            // 同步状态
            for (ChannelTonBingUserData userData : userDataMap.values()) {
                syncBaseDataMsg(userData);
                // 跨服同步用户数据到游戏服
                syncUserDataToGameServer(userData, false);
            }
        }

        // 日志
        for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
            ChannelAutoLogMgr.add(new LogChannelTonBingLockUnion(
                    config.getActivityInfo().getActivityId(),
                    join.getUnionUid(),
                    join.getCampId(),
                    join.getUnionBaseInfo().getTotalEarnSpeed().toString(),
                    join.getCampId() == 0 ? "-1" : join.getTotalAbility() + "",
                    join.getCampId() != 0 ? 1 : 0
            ));
        }
    }

    //渠道锁阵营，一个渠道一个阵营，不是三个渠道不给玩
    public void lockUnionChannel(Map<Integer, LinkedList<ActivityUnionInfo>> channelUnionMap) {
        synchronized (lock) {
            lockUnionChannelMsg(channelUnionMap);
            if (getChannelTonBingDataMain().isLockUnion()) {
                return;
            }

            // 排序拿前几名
            List<ChannelTonBingUnionJoin> rankList = unionJoinMap.values().stream()
                    .sorted(new Comparator<ChannelTonBingUnionJoin>() {
                        @Override
                        public int compare(ChannelTonBingUnionJoin o1, ChannelTonBingUnionJoin o2) {
                            // 922 3372 0368亿
                            return Long.compare(o2.getTotalAbility(), o1.getTotalAbility());
                        }
                    })
                    .limit(config.getUnionNum())
                    .collect(Collectors.toList());

            // 分阵营
            lockCampChannel(rankList);

            // 改状态
            getChannelTonBingDataMain().setLockUnion(true);
            logger.error("tonbing activity {} lock union.", config.getActivityInfo().getActivityId());

            // 移动玩家到起始点 到对应的比赛中去做这件事情了
//            channelTonBingInitTeamPosTask();

            // 初始化榜单，让0值的也上榜，才能看到自己阵营都有谁
            initAllRankList();

            // 同步状态
            for (ChannelTonBingUserData userData : userDataMap.values()) {
                syncBaseDataMsg(userData);
                // 跨服同步用户数据到游戏服
                syncUserDataToGameServer(userData, false);
            }
        }

        // 日志
        for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
            ChannelAutoLogMgr.add(new LogChannelTonBingLockUnion(
                    config.getActivityInfo().getActivityId(),
                    join.getUnionUid(),
                    join.getCampId(),
                    join.getUnionBaseInfo().getTotalEarnSpeed().toString(),
                    join.getCampId() == 0 ? "-1" : join.getTotalAbility() + "",
                    join.getCampId() != 0 ? 1 : 0
            ));
        }
    }

    /**
     * 锁定阵营
     */
    private void lockCamp(List<ChannelTonBingUnionJoin> unionJoinList) {
        synchronized (lock) {
            if (getChannelTonBingDataMain().isLockUnion()) {
                return;
            }

            // 容错：先清空锁定数据
            for (ChannelTonBingUserData userData : userDataMap.values()) {
                if (isAble(userData)) {
                    userData.setCampId(0);
                    userData.setUnionUid("");
                }
            }
            for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
                if (isAble(join)) {
                    join.setCampId(0);
                }
            }

            // 按门客赚钱重新排序
            unionJoinList = unionJoinList.stream().sorted(new Comparator<ChannelTonBingUnionJoin>() {
                @Override
                public int compare(ChannelTonBingUnionJoin o1, ChannelTonBingUnionJoin o2) {
                    return Long.compare(o2.getTotalAbility(), o1.getTotalAbility());
                }
            }).collect(Collectors.toList());

            Map<Integer, Long> campAbilityMap = new ConcurrentHashMap<>();
            Map<Integer, List<String>> campUnionMap = new ConcurrentHashMap<>();

            int campNum = config.getCampNum();
            int campUnionNum = BigDecimal.valueOf(Math.min(config.getUnionNum(), unionJoinList.size())) // 配置数量和实际数量取最小
                    .divide(BigDecimal.valueOf(config.getCampNum()), 0, BigDecimal.ROUND_UP).intValue();
            for (int i = 1; i <= campNum; i++) {
                campAbilityMap.put(i, 0L);
                campUnionMap.put(i, new ArrayList<>());
            }

            // 遍历商会一个个分配
            for (ChannelTonBingUnionJoin join : unionJoinList) {
                int minCamp = 1;
                long minAbility = Long.MAX_VALUE;
                for (Map.Entry<Integer, Long> entry : campAbilityMap.entrySet()) {
                    // 跳过已经分配满的阵营
                    if (campUnionMap.get(entry.getKey()).size() >= campUnionNum) {
                        continue;
                    }
                    // 取总赚钱最小的阵营（赚钱相同时，随机一下，避免一直一样）
                    if (entry.getValue() < minAbility ||
                            entry.getValue() == minAbility && randomHelper.next(2) == 0) {
                        minCamp = entry.getKey();
                        minAbility = entry.getValue();
                    }
                }

                long sum = join.getTotalAbility();
                campAbilityMap.put(minCamp, campAbilityMap.get(minCamp) + sum);
                campUnionMap.get(minCamp).add(join.getUnionUid());

                // 修改数据
                join.setCampId(minCamp);
                for (ChannelTonBingUnionJoinMember member : join.getMemberMap().values()) {
                    ChannelTonBingUserData userData = getUserData(member.getUserId());
                    userData.setCampId(join.getCampId());
                    userData.setUnionUid(join.getUnionUid());
                }
            }

            // 阵营数据生成
            initCampUserData();
            initGroup();
            initGroupMatchTask();
        }
    }

    private void lockCampChannel(List<ChannelTonBingUnionJoin> unionJoinList) {
        synchronized (lock) {
            if (getChannelTonBingDataMain().isLockUnion()) {
                return;
            }

            // 容错：先清空锁定数据
            for (ChannelTonBingUserData userData : userDataMap.values()) {
                if (isAble(userData)) {
                    userData.setCampId(0);
                    userData.setUnionUid("");
                }
            }

            for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
                if (isAble(join)) {
                    join.setCampId(0);
                }
            }

            Map<Integer, List<ChannelTonBingUnionJoin>> channelMap = new ConcurrentHashMap<>();
            for (ChannelTonBingUnionJoin join : unionJoinList) {
                if (!channelMap.containsKey(join.getChannelId())) {
                    channelMap.put(join.getChannelId(), new LinkedList<>());
                }
                channelMap.get(join.getChannelId()).add(join);
            }

            for (int channelId : channelMap.keySet()) {
                List<ChannelTonBingUnionJoin> unionJoins = channelMap.get(channelId);
                unionJoins = unionJoins.stream().sorted(new Comparator<ChannelTonBingUnionJoin>() {
                    @Override
                    public int compare(ChannelTonBingUnionJoin o1, ChannelTonBingUnionJoin o2) {
                        return Long.compare(o2.getTotalAbility(), o1.getTotalAbility());
                    }
                }).collect(Collectors.toList());
                channelMap.put(channelId, unionJoins);
            }


            List<Integer> campIdList = new ArrayList<>();
            for (int campId = 1; campId <= config.getCampNum(); campId++) {
                campIdList.add(campId);
            }

            // 遍历商会一个个分配
            for (int channelId : channelMap.keySet()) {
                List<ChannelTonBingUnionJoin> unionMap = channelMap.get(channelId);
                //随机一个阵营
                int campIdIndex = randomHelper.next(0, campIdList.size());
                int campId = campIdList.get(campIdIndex);
                campIdList.remove(campIdIndex);
                for (ChannelTonBingUnionJoin join : unionMap) {
                    // 修改数据
                    join.setCampId(campId);
                    for (ChannelTonBingUnionJoinMember member : join.getMemberMap().values()) {
                        ChannelTonBingUserData userData = getUserData(member.getUserId());
                        userData.setCampId(join.getCampId());
                        userData.setUnionUid(join.getUnionUid());
                    }
                }
            }

            // 阵营数据生成
            initCampUserData();
            initGroup();
            initGroupMatchTask();
        }
    }

    //先随便分组初始的第一场分
    private void initGroup() {
        List<Integer> warTypeList = config.getWarTypeList();
        Map<Integer, Map<Integer, Map<Integer, List<String>>>> turnMap = new ConcurrentHashMap<>();
        //第一轮
        turnMap.put(1, new ConcurrentHashMap<>());
        //战场1
        turnMap.get(1).put(warTypeList.get(0), new ConcurrentHashMap<>());
        for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
            if (!turnMap.get(1).get(warTypeList.get(0)).containsKey(join.getCampId())) {
                turnMap.get(1).get(warTypeList.get(0)).put(join.getCampId(), new ArrayList<>());
            }
            turnMap.get(1).get(warTypeList.get(0)).get(join.getCampId()).add(join.getUnionUid());
        }
        channelTonBingDataMain.setTurnUnionMap(turnMap);
        channelTonBingDataMain.setWinnerMap(new ConcurrentHashMap<>());
    }

    //第二天了结束掉前一天的比赛，开始进行晋级
    private void checkGameOver() {
        int matchMaxTurn = 0;
        for (int turn : turnMatchMap.keySet()) {
            if (matchMaxTurn < turn) {
                matchMaxTurn = turn;
            }
        }
        Map<Integer, Map<Integer, List<String>>> upMap = new ConcurrentHashMap<>();
        int nowConfigTurn = config.getTurn();
        if (nowConfigTurn == 0) {
            return;
        }
        int upTurn = nowConfigTurn;
        if (matchMaxTurn + 1 < nowConfigTurn) {
            upTurn = matchMaxTurn + 1;
        }
        int lastTurn = upTurn - 1;
        //没有当前的分组，结束上一轮开始生成
        if (!turnMatchMap.containsKey(upTurn)) {
            if (turnMatchMap.containsKey(lastTurn)) {
                for (int warType : turnMatchMap.get(lastTurn).keySet()) {
                    for (ChannelTonBingMatch match : turnMatchMap.get(lastTurn).get(warType).values()) {
                        if (!match.isGameOver()) {
                            match.setGameOver(true);
                            match.setStop(true);
                            Map<Integer, Map<Integer, List<String>>> riseMap = riseMatchUnion(match);
                            for (int riseWarType : riseMap.keySet()) {
                                if (!upMap.containsKey(riseWarType)) {
                                    upMap.put(riseWarType, new ConcurrentHashMap<>());
                                }
                                for (int riseCampId : riseMap.get(riseWarType).keySet()) {
                                    if (!upMap.get(riseWarType).containsKey(riseCampId)) {
                                        upMap.get(riseWarType).put(riseCampId, new ArrayList<>());
                                    }
                                    upMap.get(riseWarType).get(riseCampId).addAll(riseMap.get(riseWarType).get(riseCampId));
                                }
                            }
                        }
                    }
                }
                Map<Integer, Map<Integer, Map<Integer, List<String>>>> turnMap = channelTonBingDataMain.getTurnUnionMap();
                if (!turnMap.containsKey(upTurn)) {
                    turnMap.put(upTurn, new ConcurrentHashMap<>());
                }
                turnMap.get(upTurn).putAll(upMap);
                channelTonBingDataMain.setTurnUnionMap(turnMap);
                logger.error("晋级完成{}轮次", upTurn);
                initAllRankList();
            }
        }
    }

    //晋级商会，没晋级的原地保留 战场 阵营
    private Map<Integer, Map<Integer, List<String>>> riseMatchUnion(ChannelTonBingMatch match) {
        logger.error("开始晋级比赛{}", match.getChannelTonBingData().getMatchId());
        int turn = match.getChannelTonBingData().getTurn();
        int wayType = match.getChannelTonBingData().getWarType();
        int riseNum = config.getGroupRuleList(turn);
        Map<Integer, Map<Integer, List<String>>> resMap = new ConcurrentHashMap<>();
        Map<String, ChannelTonBingUnionJoin> unionMap = match.getUnionJoinMap();
        Map<Integer, List<ChannelTonBingRank>> campUnionMap = new ConcurrentHashMap<>();
        resMap.put(wayType, new ConcurrentHashMap<>());
        resMap.put(wayType + 1, new ConcurrentHashMap<>());
        Map<Integer, ChannelTonBingRankListModel> matchCampUnionRankMap = match.getCampUnionRankMap();
        for (int campId : matchCampUnionRankMap.keySet()) {
            if (!campUnionMap.containsKey(campId)) {
                campUnionMap.put(campId, new ArrayList<>());
            }
            ChannelTonBingRankListModel model = matchCampUnionRankMap.get(campId);
            for (ChannelTonBingRank rank : model.getRankList()) {
                campUnionMap.get(campId).add(rank);
            }
        }
        /*for(ChannelTonBingUnionJoin join : unionMap.values()){
            ChannelTonBingRise riseData = new ChannelTonBingRise();
            riseData.setUnionId(join.getUnionUid());
            riseData.setZhangong(getUnionZhangong(join));
            if(!campUnionMap.containsKey(join.getCampId())){
                campUnionMap.put(join.getCampId(),new ArrayList<>());
            }
            campUnionMap.get(join.getCampId()).add(riseData);
        }*/
        for (int campId : campUnionMap.keySet()) {
            List<ChannelTonBingRank> riseList = campUnionMap.get(campId);
            logger.info("阵营{}的排行榜数据", campId);
            riseList.sort(new ChannelTonBingRankSort());
            for (ChannelTonBingRank rank : riseList) {
                logger.info("阵营{},商会{},战功{}", campId, rank.getId(), rank.getValue());
            }
            int index = 0;
            for (ChannelTonBingRank riseData : riseList) {
                if (index < riseNum) {
                    if (!resMap.get(wayType + 1).containsKey(campId)) {
                        resMap.get(wayType + 1).put(campId, new ArrayList<>());
                    }
                    resMap.get(wayType + 1).get(campId).add(riseData.getId());
                    logger.info("阵营{},商会{},晋级下一轮", campId, riseData.getId());
                } else {
                    if (!resMap.get(wayType).containsKey(campId)) {
                        resMap.get(wayType).put(campId, new ArrayList<>());
                    }
                    resMap.get(wayType).get(campId).add(riseData.getId());
                    logger.info("阵营{},商会{},晋级失败", campId, riseData.getId());
                }
                index++;
            }
        }
        for (int warType : resMap.keySet()) {
            if (resMap.get(warType).size() == 0) {
                resMap.remove(warType);
            }
        }
        return resMap;
    }

    class UnionZhangongSort implements Comparator<ChannelTonBingRise> {
        @Override
        public int compare(ChannelTonBingRise o1, ChannelTonBingRise o2) {
            if (o1.getZhangong() == o2.getZhangong()) {
                return 0;
            }
            if (o1.getZhangong() > o2.getZhangong()) {
                return -1;
            }
            return 1;
        }
    }


    private long getUnionZhangong(ChannelTonBingUnionJoin unionJoin) {
        long myValue = 0;
        for (ChannelTonBingUnionJoinMember member : unionJoin.getMemberMap().values()) {
            ChannelTonBingUserData tmp = getUserData(member.getUserId());
            myValue += tmp.getZhanGong();
        }
        return myValue;
    }

    public void initGroupMatchTask() {
        long next5Second = System.currentTimeMillis() + DateHelper.SECOND_MILLIONS + 5000;
        addTask(new ChannelTonBingMakeMatchTask(this, next5Second));
        //榜单还没锁定不用这里操作
        if (channelTonBingDataMain.isLockUnion()) {
            //每一组最大多少人
            synchronized (lock) {
                int turn = config.getTurn();
                if (turn != 0) {
                    checkGameOver();
                    //要是中间开始前面的也要生成
                    for (int i = 1; i <= turn; i++) {
                        if (!channelTonBingDataMain.getTurnUnionMap().containsKey(i)) {
                            continue;
                        }
                        if (turnMatchMap.containsKey(i)) {
                            continue;
                        }
                        makeGroupMatch(i);
                    }
                }
            }
        }
    }

    class GroupRankSort implements Comparator<ChannelTonBingRank> {
        @Override
        public int compare(ChannelTonBingRank o1, ChannelTonBingRank o2) {
            return Long.compare(o2.getValue(), o1.getValue());
        }
    }

    //生成比赛
    private void makeGroupMatch(int turn) {
        long startMakeTime = System.currentTimeMillis();
        Map<Integer, Integer> campIdRankMap = new ConcurrentHashMap<>();
        //第一轮没有上一轮的排名,用来报错阵营排名产出辎重的buff
        if (turn != 1) {
            LinkedList<ChannelTonBingRank> rankList = getCampScoreRankList();
            int rank = 1;
            for (ChannelTonBingRank rankInfo : rankList) {
                campIdRankMap.put(Integer.valueOf(rankInfo.getId()), rank);
                rank++;
            }
            //不自己写了，用排行榜的吧
            /*List<ChannelTonBingRank> rankList = new ArrayList<>();
            Map<Integer,Integer> campIdIntMap = new ConcurrentHashMap<>();
            Map<Integer,Map<Integer,Map<Integer,Long>>> mmMap = getCampValueMap();
            for(Map<Integer,Map<Integer,Long>> dataMap : mmMap.values()){
                Map<Integer,Long> intMap = dataMap.get(2);//积分
                for(int cId : intMap.keySet()){
                    campIdIntMap.put(cId,campIdIntMap.getOrDefault(cId,0));
                }
            }
            if(campIdIntMap.size() > 0){
                for(int campId : campIdIntMap.keySet()){
                    ChannelTonBingRank rank = new ChannelTonBingRank();
                    rank.setId(campId + "");
                    rank.setValue(campIdIntMap.get(campId));
                    rankList.add(rank);
                }
                rankList.sort(new GroupRankSort());
                int rank = 1;
                for(ChannelTonBingRank rankInfo : rankList){
                    campIdRankMap.put(Integer.valueOf(rankInfo.getId()),rank);
                    rank++;
                }
            }*/
        }

        int unionMax = config.getUnionMax();
        Map<Integer, Map<Integer, Map<Integer, List<String>>>> turnMap = channelTonBingDataMain.getTurnUnionMap();
        if (!turnMap.containsKey(turn)) {
            return;
        }
        Map<Integer, Map<Integer, List<String>>> warTypeMap = turnMap.get(turn);
        Map<Integer, Map<Integer, Map<String, Long>>> newMap = makeMatchRankUnion(warTypeMap);
        for (int warType : newMap.keySet()) {
            Map<Integer, Map<String, Long>> campUnionIdMap = newMap.get(warType);
            //当达不到配置数的商会的时候用最大的分组来分，就不会出现有商会被落下了
            int allCount = 0;
            int maxCount = 0;
            for (int campId : campUnionIdMap.keySet()) {
                if (campUnionIdMap.get(campId).size() > maxCount) {
                    maxCount = campUnionIdMap.get(campId).size();
                }
                allCount += campUnionIdMap.get(campId).size();

            }
            int moreUnionCount = allCount % (unionMax * config.getCampNum());
            int groupCount = allCount / (unionMax * config.getCampNum());
            if (moreUnionCount != 0) {
                groupCount = groupCount + 1;
            }
            //生成每一个租的商会数据
            //组id campId 商会列表
            Map<Integer, Map<Integer, List<String>>> groupMap = new ConcurrentHashMap<>();
            //组id campId 总赚钱
            Map<Integer, Map<Integer, Long>> groupZhuanqianMap = new ConcurrentHashMap<>();
            for (int i = 0; i < groupCount; i++) {
                groupMap.put(i + 1, new ConcurrentHashMap<>());
                groupZhuanqianMap.put(i + 1, new ConcurrentHashMap<>());
                for (int cp = 1; cp <= config.getCampNum(); cp++) {
                    groupMap.get(i + 1).put(cp, new ArrayList<>());
                    groupZhuanqianMap.get(i + 1).put(cp, 0L);
                }
            }
            while (campUnionIdMap.size() > 0) {
                for (int campId : campUnionIdMap.keySet()) {
                    List<ChannelTonBingRank> rankList = new ArrayList<>();
                    //商会也要排一下再去生成按顺序从大到小来
                    for (String unionId : campUnionIdMap.get(campId).keySet()) {
                        ChannelTonBingRank rank = new ChannelTonBingRank(unionId, campUnionIdMap.get(campId).get(unionId), 0);
                        rankList.add(rank);
                    }
                    rankList.sort(new ChannelTonBingRankSort());
                    for (ChannelTonBingRank rank : rankList) {
                        addUnionToGroup(groupMap, groupZhuanqianMap, campUnionIdMap, rank.getId(), campId);
                    }
                }
            }

            List<ChannelTonBingMatch> matchList = new ArrayList<>();
            //比赛生成然后轮流加人
            for (int i = 0; i < groupCount; i++) {
                ChannelTonBingMatch match = new ChannelTonBingMatch(config, null);
                match.initMatchData(turn, warType, matchId.getAndIncrement());
                for (List<String> unionIdList : groupMap.get(i + 1).values()) {
                    for (String unionId : unionIdList) {
                        match.getUnionJoinMap().put(unionId, unionJoinMap.get(unionId));
                    }
                }
                matchList.add(match);
            }
            for (ChannelTonBingMatch match : matchList) {
                addTurnMatch(match);
                List<ChannelTonBingUserData> userDataList = new ArrayList<>();
                for (ChannelTonBingUnionJoin unionJoin : match.getUnionJoinMap().values()) {
                    for (long userId : unionJoin.getMemberMap().keySet()) {
                        ChannelTonBingUserData userData = getUserData(userId);
                        userDataList.add(userData);
                        userMatchMap.put(userData.getUserId(), match);
                    }
                }
                match.initUserData(userDataList);
                match.saveLastRank(campIdRankMap);
                match.initData();
                match.start();
            }
        }
        for(int warType : turnMatchMap.get(turn).keySet()){
            Map<Integer,ChannelTonBingMatch> warTypeMatchMap = turnMatchMap.get(turn).get(warType);
            for(ChannelTonBingMatch match : warTypeMatchMap.values()){
                for(ChannelTonBingUnionJoin join : match.getUnionJoinMap().values()){
                    ChannelAutoLogMgr.add(new LogChannelTonBingUnionPeak(
                            config.getActivityInfo().getActivityId(),
                            join.getUnionUid(),
                            turn,
                            join.getCampId(),
                            warType,
                            turn == warType ? 1 : 0,
                            match.getChannelTonBingData().getMatchId()
                    ));
                }
            }
        }
        for (ChannelTonBingUserData userData : userDataMap.values()) {
            syncBaseDataMsg(userData);
            syncUserDataToGameServer(userData, true);
        }
        long endMakeTime = System.currentTimeMillis();
        logger.info("第{}轮比赛生成花费时间{}毫秒", turn, endMakeTime - startMakeTime);
    }

    //获得当前的战场的最小赚钱的组且没有达到
    private int addUnionToGroup(Map<Integer, Map<Integer, List<String>>> groupMap,
                                Map<Integer, Map<Integer, Long>> groupZhuanqianMap,
                                Map<Integer, Map<String, Long>> campUnionIdMap,
                                String unionId,
                                int campId) {
        int unionMax = config.getUnionMax();
        List<ChannelTonBingRank> rankList = new ArrayList<>();
        for (Integer groupId : groupZhuanqianMap.keySet()) {
            if (groupMap.get(groupId).get(campId).size() >= unionMax) {
                continue;
            }
            Map<Integer, Long> campZhuanqianMap = groupZhuanqianMap.get(groupId);
            ChannelTonBingRank rank = new ChannelTonBingRank(groupId + "", campZhuanqianMap.getOrDefault(campId, 0L), 0);
            rankList.add(rank);
        }
        if (!rankList.isEmpty()) {
            rankList.sort(new ChannelTonBingRankSort());
            ChannelTonBingRank selectRank = rankList.get(rankList.size() - 1);
            groupMap.get(Integer.valueOf(selectRank.getId())).get(campId).add(unionId);
            groupZhuanqianMap.get(Integer.valueOf(selectRank.getId())).put(campId,
                    groupZhuanqianMap.get(Integer.valueOf(selectRank.getId())).getOrDefault(campId, 0L) +
                            campUnionIdMap.get(campId).get(unionId));
        }
        campUnionIdMap.get(campId).remove(unionId);
        if (campUnionIdMap.get(campId).size() == 0) {
            campUnionIdMap.remove(campId);
        }
        return 1;
    }

    //把所有战场和对应阵营的商会排名下
    private Map<Integer, Map<Integer, Map<String, Long>>> makeMatchRankUnion(Map<Integer, Map<Integer, List<String>>> warTypeMap) {
        Map<Integer, Map<Integer, Map<String, Long>>> newMap = new ConcurrentHashMap<>();
        for (int warType : warTypeMap.keySet()) {
            newMap.put(warType, new ConcurrentHashMap<>());
            Map<Integer, List<String>> campUnionMap = warTypeMap.get(warType);
            for (int campId : campUnionMap.keySet()) {
                newMap.get(warType).put(campId, new ConcurrentHashMap<>());
                List<ChannelTonBingRank> rankList = new ArrayList<>();
                for (String unionId : campUnionMap.get(campId)) {
                    ChannelTonBingUnionJoin unionJoin = getUnionJoin(unionId);
                    ChannelTonBingRank rank = new ChannelTonBingRank(unionId, unionJoin.getTotalAbility(), 0);
                    rankList.add(rank);
                }
                rankList.sort(new ChannelTonBingRankSort());
                for (ChannelTonBingRank rank : rankList) {
                    newMap.get(warType).get(campId).put(rank.getId(), rank.getValue());
                }
            }
        }
        return newMap;
    }

    //把对应的比赛加入
    private void addTurnMatch(ChannelTonBingMatch match) {
        ChannelTonBingData data = match.getChannelTonBingData();
        if (!turnMatchMap.containsKey(data.getTurn())) {
            turnMatchMap.put(data.getTurn(), new ConcurrentHashMap<>());
        }
        if (!turnMatchMap.get(data.getTurn()).containsKey(data.getWarType())) {
            turnMatchMap.get(data.getTurn()).put(data.getWarType(), new ConcurrentHashMap<>());
        }
        turnMatchMap.get(data.getTurn()).get(data.getWarType()).put(data.getMatchId(), match);
        matchMap.put(data.getMatchId(), match);
    }

    /**
     * 初始化阵营数据
     */
    private void initCampUserData() {

        logger.info("initCampUserData activityId {}.", config.getActivityInfo().getActivityId());

        // 阵营数据生成
        for (int campId = 1; campId <= config.getCampNum(); campId++) {
            if (!campDataMap.containsKey(campId)) {
                ChannelTonBingCampData campData = new ChannelTonBingCampData();
                campData.setActivityId(config.getActivityInfo().getActivityId());
                campData.setCampId(campId);
                campData.setInsertOption();
                campDataMap.put(campId, campData);
            } else {
                // 已有数据说明有问题...
                logger.error("ton bing initCampUserData, repeated create data? activityId {}, campId {}.", config.getActivityInfo().getActivityId(), campId);
                ChannelTonBingCampData campData = campDataMap.get(campId);
                campData.setRedPacketMap(new ConcurrentHashMap<>());
                campData.setRedPacketValue(0L);
                campData.setUserRedPacketMap(new ConcurrentHashMap<>());
                campDataMap.put(campId, campData);
            }
        }
    }


    /**
     * 是否有资格
     */
    private boolean isAble(ChannelTonBingUserData userData) {
        if (userData == null) {
            return false;
        }
        return userData.getCampId() != 0;
    }

    /**
     * 是否有资格
     */
    private boolean isAble(ChannelTonBingUnionJoin join) {
        return join.getCampId() != 0;
    }

    public ChannelTonBingMatch getMatchByUnionId(String unionId) {
        int turn = config.getTurn();
        Map<Integer, Map<Integer, ChannelTonBingMatch>> typeMatchMap = new ConcurrentHashMap<>(turnMatchMap.get(turn));
        for (int type : typeMatchMap.keySet()) {
            Map<Integer, ChannelTonBingMatch> matchMap = new ConcurrentHashMap<>(typeMatchMap.get(type));
            for (ChannelTonBingMatch match : matchMap.values()) {
                if (match.getUnionJoin(unionId) != null) {
                    return match;
                }
            }
        }
        return null;
    }

    public ChannelTonBingMatch getMatchByUserId(long userId) {
        if (!userMatchMap.containsKey(userId)) {
            return null;
        }
        return userMatchMap.get(userId);
    }

    public ChannelTonBingMatch getMatchByMatchId(int matchId) {
        if (!matchMap.containsKey(matchId)) {
            return null;
        }
        return matchMap.get(matchId);
    }
    // ============================== 队伍 ==============================

    /**
     * 更新门客数据（没资格也可以更新，不然游戏第一次进来没有值）
     *
     * @param first               首次同步不用设置CD，队伍士兵补满
     * @param isRefreshMaxSoldier 是否只刷新兵力上限
     */
    private int updatePatronsAbility(ChannelTonBingUserData userData, boolean first, Map<Integer, ChannelTonBingPatrons> patronsMap, List<Long> addition, boolean isRefreshMaxSoldier) {
        ChannelTonBingMatch match = getMatchByUserId(userData.getUserId());
        if (match != null) {
            return match.updatePatronsAbility(userData, first, patronsMap, addition, isRefreshMaxSoldier);
        }
        return 0;
    }

    // ============================== CMD ==============================

    public boolean loginByCmd(long userId, ChannelTonBingProto.ChannelTonBingLoginReqMsg reqMsg) {
        ChannelTonBingUserData userData = getUserData(userId);
        if (userData == null) {
            return false;
        }
        ChannelTonBingMatch match = getMatchByUserId(userId);

//        if (userData.getChannelId() == 0 || userData.getServerId() == 0) {
//            userData.setServerId(reqMsg.getServerId());
//            userData.setChannelId(reqMsg.getChannelId());
//        }
        //锁商会的时候主动拉一次,不要每次登录都上传//先保留原有逻辑
        // 第一次帮他同步
        if (userData.getPatronsMap().isEmpty()) {
            updatePatronsAbility(userData, true, ChannelTonBingPb.parseChannelTonBingPatrons(reqMsg.getPatronsListList()), reqMsg.getSoldierAdditionList(), false);
        }
        // 同步数据
        syncBaseDataMsg(userData);
        // 跨服同步用户数据到游戏服
        syncUserDataToGameServer(userData, false);
        //任命了别人别人可能没在线，登录的时候再同步一次
        syncUserPosition(userId);
        // 同步战功成就
        notifyConditionChange(userId, eGamePlayerEventType.TonBingZhanGong, userData.getZhanGong());
        // 同步全部红点
        if (config.inShowActivityTime()) {
            ChannelTonBingProto.CTonBingSyncRedDotRespMsg.Builder builder = ChannelTonBingProto.CTonBingSyncRedDotRespMsg.newBuilder();
            builder.addAllType(userData.getRedDotMap().keySet());
            sendChannelPacket(ClientProtocol.U_CTON_BING_SYNC_RED_DOT, builder, userData);
        }

        if (match != null) {
            // 同步阵营指挥官
            match.syncCommanderInfo(userId, userData.getCampId());
        }

        return userData.getCampId() != 0;
    }

    private ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.Builder parsePosAppoint(ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.Builder msg, Map<Integer, Integer> positionMap) {
        Map<Integer, Integer> posMap = new ConcurrentHashMap(positionMap);
        for (int type : posMap.keySet()) {
            ChannelTonBingProto.CTonBingPositionMsg.Builder posMsg = ChannelTonBingProto.CTonBingPositionMsg.newBuilder();
            posMsg.setType(type);
            posMsg.setPositionId(posMap.get(type));
            msg.addPosition(posMsg);
        }
        return msg;
    }

    private ChannelTonBingProto.CTonBingUserPositionMsg.Builder parsePosUser(ChannelTonBingProto.CTonBingUserPositionMsg.Builder msg, Map<Integer, Integer> positionMap) {
        Map<Integer, Integer> posMap = new ConcurrentHashMap(positionMap);
        for (int type : posMap.keySet()) {
            ChannelTonBingProto.CTonBingPositionMsg.Builder posMsg = ChannelTonBingProto.CTonBingPositionMsg.newBuilder();
            posMsg.setType(type);
            posMsg.setPositionId(posMap.get(type));
            msg.addPosition(posMsg);
        }
        return msg;
    }

    private void syncUserPosition(long userId) {
        UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo != null) {
            ChannelTonBingUserData userData = getUserData(userId);
            if (userData == null) {
                return;
            }
            if (isAble(userData) && userData.getPositionMap().size() != 0) {
                ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.Builder crespMsg = ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.newBuilder();
                crespMsg.setWinerName("");
                parsePosAppoint(crespMsg, userData.getPositionMap());
                crespMsg.setCampId(userData.getCampId());
                crespMsg.setSendReward(false);
                sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_CITY_APPOINT_POSITION, crespMsg, userData);
            }
        }
    }

    public void notifyUnionMemberChangeByCmd(String unionUid) {
        // 没报名，不管
        ChannelTonBingUnionJoin unionJoin = getUnionJoin(unionUid);
        if (unionJoin == null) {
            return;
        }
        // 结束了，不管
        if (System.currentTimeMillis() > config.getActivityInfo().getEndTime() * 1000L) {
            return;
        }
        // 重新拉一下商会成员数据
        sendGetUnionMsg(unionUid);
    }

    public void syncPatronsByCmd(ChannelTonBingProto.ChannelTonBingUpdatePatronsReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(reqMsg.getUserId());
        if (match != null) {
            match.syncPatronsByCmd(reqMsg);
        }
    }

    public void syncUserPositionSliver() {
        Map<Long, List<ChannelTonBingUserData>> needSyncUserDataMap = new ConcurrentHashMap<>(getNeedSyncPosUserDataMap());
        for (Long serverId : needSyncUserDataMap.keySet()) {
            ChannelTonBingProto.ChannelTonBingPositionSliverSyncMsg.Builder syncMsg = ChannelTonBingProto.ChannelTonBingPositionSliverSyncMsg.newBuilder();
            List<ChannelTonBingUserData> userDataList = needSyncPosUserData.get(serverId);
            for (ChannelTonBingUserData userData : userDataList) {
                ChannelTonBingProto.ChannelTonBingPositionUserMsg.Builder userMsg = ChannelTonBingProto.ChannelTonBingPositionUserMsg.newBuilder();
                userMsg.setUserId(userData.getUserId());
                Map<Long, BigInteger> addMap = userData.getPosAddSilverMap();
                for (long userId : addMap.keySet()) {
                    UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
                    if (userBaseInfo != null) {
                        ChannelTonBingProto.CTonBingPositionSliverMsg.Builder sliverUserMsg = ChannelTonBingProto.CTonBingPositionSliverMsg.newBuilder();
                        sliverUserMsg.setUserId(userId);
                        sliverUserMsg.setSliver(addMap.get(userId).toString());
                        sliverUserMsg.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                        userMsg.addSliverUser(sliverUserMsg);
                    }
                }
                syncMsg.addUser(userMsg);
            }
            //这个需求没了，不用管了
            for (int channelId : channelIdList) {
                if (ChannelActivityUnionMgr.isServerIdInChannel(serverId, channelId)) {
                    sendChannelPacket(GameProtocol.S_CTON_BING_POS_REWARD_SYNC, syncMsg, serverId, channelId);
                }
            }
        }
    }


    /**
     * 设置战略目标
     */
    public void setTargetCityByCmd(long userId, ChannelTonBingProto.CTonBingSetTargetCityReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.setTargetCityByCmd(userId, reqMsg);
        }
    }

    public void moveTeamByCmd(long userId, ChannelTonBingProto.CTonBingMoveTeamReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.moveTeamByCmd(userId, reqMsg);
        }
    }

    public void speedUpByCmd(long userId, ChannelTonBingProto.CTonBingMoveSpeedUpReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.speedUpByCmd(userId, reqMsg);
        }
    }

    //检查一下门客有没有，一般是会有的，测试时间调来调去会导活动乱七八糟会导致没有
    private void checkPatrons(long userId) {
        ChannelTonBingUserData userData = getUserData(userId);
        if (userData == null) {
            return;
        }
        if (userData.getCampId() != 0) {
            if (userData.getPatronsMap().size() == 0) {
                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
                if (userBaseInfo != null) {
                    ChannelTonBingProto.CTonBingUpdatePatronsAbilityReqMsg.Builder msg = ChannelTonBingProto.CTonBingUpdatePatronsAbilityReqMsg.newBuilder();
                    sendChannelPacket(GameProtocol.S_CTON_BING_UPDATE_PATRONS_ABILITY, msg, userData);
                }
            }
        }
    }

    public void getDataByCmd(long userId, int matchId, int channelId, long serverId) {
        if (matchId == 0) {
            watchMap.remove(userId);
        }
        for (ChannelTonBingMatch match : matchMap.values()) {
            match.removeWatchPlayer(userId);
        }
        ChannelTonBingMatch match = getMatchByMatchId(matchId);
        if (match != null) {
            match.getDataByCmd(userId, channelId, serverId);
            watchMap.put(userId, matchId);
        }

        // 同步高亮玩家
        syncLight(userId, channelId, serverId);
    }

    public void getMyTeamPosByCmd(long userId, ChannelTonBingProto.CTonBingGetBattlefieldMyTeamReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.getMyTeamPosByCmd(userId, reqMsg);
        }
    }

    public void getPosReward(long serverId, long userId) {
        ChannelTonBingProto.CTonBingPosGetRewardRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingPosGetRewardRespMsg.newBuilder();
        respMsg.setRet(0);
        ChannelTonBingUserData userData = getUserData(userId);
        if (!isAble(userData)) {
            respMsg.setRet(GameErrorCode.E_TON_BING_NO_ABLE);
            sendChannelPacket(ClientProtocol.U_CTON_BING_GET_POS_REWARD, respMsg, userData);
            return;
        }
        synchronized (lock) {
            if (userData.getPositionMap().size() == 0) {
                respMsg.setRet(GameErrorCode.E_TON_BING_POS_REWARD_CAN_NOT_GET);
                sendChannelPacket(ClientProtocol.U_CTON_BING_GET_POS_REWARD, respMsg, userData);
                return;
            }
            Map<Integer, Map<Integer, ChannelTonBingTitleConfig>> titleConfigMap = config.getTitleConfigMap();
            Map<Long, BigInteger> rewardMap = userData.getPosAddSilverMap();
            BigInteger allValue = BigInteger.ZERO;
            Map<Integer, Integer> posMap = userData.getPositionMap();
            for (int posType : posMap.keySet()) {
                ChannelTonBingTitleConfig titleConfig = titleConfigMap.get(posType).get(posMap.get(posType));
                if (titleConfig.getType() != 1) {
                    continue;
                }
                for (long unLuckUserId : rewardMap.keySet()) {
                    BigInteger value = rewardMap.get(unLuckUserId);
                    allValue = allValue.add(value);
                    rewardMap.put(unLuckUserId, BigInteger.ZERO);
                    userData.setUpdateOption();
                }
            }

            if (allValue.compareTo(BigInteger.ZERO) == 0) {
                respMsg.setRet(GameErrorCode.E_TON_BING_NO_POS_REWARD);
                sendChannelPacket(ClientProtocol.U_CTON_BING_GET_POS_REWARD, respMsg, userData);
                return;
            }
            userData.setPosAddSilverMap(rewardMap);
            respMsg.setReward(GameConfig.GAME_MONEY_SILVER + "=" + allValue.toString());
        }
        sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_GET_POS_REWARD, respMsg, userData);
    }

    //获得城池战报
    public void cityWarReport(long userId) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.cityWarReport(userId);
        }
    }

    //获得个人战报
    public void userWarReport(long userId) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.userWarReport(userId);
        }
    }

    //城主信息
    //todo 遍历太多,看下怎么优化
    public void getCityWinner(long userId, int channelId, long serverId) {
//        testSendMaill();
        ChannelTonBingProto.CTonBingCityWinerRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingCityWinerRespMsg.newBuilder();
        respMsg.setRet(0);
//        long winnerUserId = channelTonBingData.getProcess2WinUserId();
        Map<Integer, Long> winnerMap = channelTonBingDataMain.getWinnerMap();
        for (int winnerType : winnerMap.keySet()) {
            Long winnerId = winnerMap.get(winnerType);
            ChannelTonBingUserData winnerData = getUserData(winnerId);
            ChannelTonBingProto.CTonBingCityWinnerMsg.Builder winnerMsg = ChannelTonBingProto.CTonBingCityWinnerMsg.newBuilder();
            winnerMsg.setType(winnerType);
            for (ChannelTonBingUserData userData : userDataMap.values()) {
                Map<Integer, Integer> posMap = userData.getPositionMap();
                //如果是皇帝，可以命名自己阵营的
                if (winnerType == 0) {
                    if (userData.getCampId() != winnerData.getCampId()) {
                        continue;
                    }
                } else {//如果是城主，可以命名自己商会的
                    if (!userData.getUnionUid().equals(winnerData.getUnionUid())) {
                        continue;
                    }
                }
                boolean needSync = posMap.containsKey(winnerType); // 有职位，必须发
                if (userId == winnerId) { // 自己是城主，就要所有人的信息
                    needSync = true;
                }
                if (!needSync) {
                    continue;
                }
                UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userData.getUserId());
                if (userBaseInfo != null) {
                    ChannelTonBingProto.CTonBingUserPositionMsg.Builder userMsg = ChannelTonBingProto.CTonBingUserPositionMsg.newBuilder();
                    userMsg.setUserId(userData.getUserId());
                    userMsg.setCampId(userData.getCampId());
                    userMsg.setZhangong(userData.getZhanGong());
                    parsePosUser(userMsg, userData.getPositionMap());
                    /*ChannelTonBingProto.CTonBingPositionMsg.Builder posMsg = ChannelTonBingProto.CTonBingPositionMsg.newBuilder();
                    if(posMap.containsKey(winnerType)){
                        posMsg.setType(winnerType);
                        posMsg.setPositionId(posMap.get(winnerType));
                        userMsg.addPosition(posMsg);
                    }*/
                    userMsg.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    userMsg.setTotalPosSilver(userData.getTotalPosSilver().toString());
                    winnerMsg.addList(userMsg);
                }
            }
            respMsg.addList(winnerMsg);
        }
        ChannelTonBingUserData userData = getUserData(userId);
        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_CITY_WINNER, respMsg, channelId, serverId, userId);
    }

    //获取玩家的赚速，任命职位的时候扣别人的赚速加到自己身上就是用这个赚速
    private BigInteger getUserEarnSpeed(long userId) {
        ChannelTonBingUserData userData = getUserData(userId);
        if (userData == null) {
            return BigInteger.ZERO;
        }
        if (unionJoinMap.containsKey(userData.getUnionUid())) {
            Map<Long, ChannelTonBingUnionJoinMember> joinMemberMap = unionJoinMap.get(userData.getUnionUid()).getMemberMap();
            if (joinMemberMap.containsKey(userId)) {
                return BigInteger.valueOf(joinMemberMap.get(userId).getEarnSpeed());
            }
        }
        return BigInteger.ZERO;
    }

    //任命职位
    public void cityWinnerAppointPosition(long userId, ChannelTonBingProto.ChannelTonBingCityWinerAppointReqMsg reqMsg) {
        ChannelTonBingUserData userData = getUserData(userId);
        ChannelTonBingProto.CTonBingCityWinerRespMsg.Builder respMsg = ChannelTonBingProto.CTonBingCityWinerRespMsg.newBuilder();
        respMsg.setRet(0);
        //吧有洛阳的城池的城主弄过来
        Map<Integer, Long> winnerMap = channelTonBingDataMain.getWinnerMap();
        if (!winnerMap.containsKey(reqMsg.getType()) || winnerMap.get(reqMsg.getType()) != userId) {
            respMsg.setRet(GameErrorCode.E_TON_BING_APPOINT_NOT_WINNER);
            sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
            return;
        }
        if (reqMsg.getPosition() == eTonBingPosition.Master.getValue()) {
            respMsg.setRet(GameErrorCode.E_TON_BING_APPOINT_NOT_WINNER);
            sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
            return;
        }
        ChannelTonBingUserData winnerUserData = getUserData(userId);
        ChannelTonBingUserData appointUserData = getUserData(reqMsg.getUserId());//任命的玩家
        synchronized (lock) {
            Map<Integer, Map<Integer, ChannelTonBingTitleConfig>> titleConfigMap = config.getTitleConfigMap();
            if (!titleConfigMap.get(reqMsg.getType()).containsKey(reqMsg.getPosition())) {
                respMsg.setRet(GameErrorCode.E_TON_BING_USER_POSITION_APPOINT_ERR);
                sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                return;
            }
            ChannelTonBingTitleConfig titleConfig = titleConfigMap.get(reqMsg.getType()).get(reqMsg.getPosition());
            Map<Integer, Integer> posMap = appointUserData.getPositionMap();
//            if (posMap.containsKey(reqMsg.getType()) && posMap.get(reqMsg.getType()) != eTonBingPosition.None.getValue()) {
            if (posMap.size() > 0) {
                respMsg.setRet(GameErrorCode.E_TON_BING_USER_POSITION_APPOINT);
                sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                return;
            }
            //任命的时候校验下是不是这个职位已经任命过了
            for (ChannelTonBingUserData userDd : new ArrayList<>(userDataMap.values())) {
                Map<Integer, Integer> posDdMap = userDd.getPositionMap();
                if (posDdMap.containsKey(reqMsg.getType()) && posDdMap.get(reqMsg.getType()) == reqMsg.getPosition()) {
                    respMsg.setRet(GameErrorCode.E_TON_BING_USER_POSITION_APPOINT_ERR);
                    sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                    return;
                }
            }
            Map<Integer, Integer> winnerPosMap = winnerUserData.getPositionMap();
            if (!winnerPosMap.containsKey(reqMsg.getType()) || winnerPosMap.get(reqMsg.getType()) != eTonBingPosition.Master.getValue()) {
                respMsg.setRet(GameErrorCode.E_TON_BING_USER_APPOINT_ERR_POSITION);
                sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                return;
            }
            //皇帝只能任命自己阵营的，城主只能任命自己商会的
            if (reqMsg.getType() == 0) {
                if (winnerUserData.getCampId() != appointUserData.getCampId()) {
                    respMsg.setRet(GameErrorCode.E_TON_BING_USER_APPOINT_ERR_POSITION);
                    sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                    return;
                }
            } else {
                if (!winnerUserData.getUnionUid().equals(appointUserData.getUnionUid())) {
                    respMsg.setRet(GameErrorCode.E_TON_BING_USER_APPOINT_ERR_POSITION);
                    sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                    return;
                }
            }
            if (winnerUserData.getCampId() == appointUserData.getCampId()) {
                if (titleConfig.getType() != 1) {
                    respMsg.setRet(GameErrorCode.E_TON_BING_USER_APPOINT_ERR_POSITION);
                    sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                    return;
                }
            } else {
                if (titleConfig.getType() != 2) {
                    respMsg.setRet(GameErrorCode.E_TON_BING_USER_APPOINT_ERR_POSITION);
                    sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
                    return;
                }
            }
            posMap.put(reqMsg.getType(), reqMsg.getPosition());
            appointUserData.setPositionMap(posMap);
            Map<Integer, Integer> appointMap = new ConcurrentHashMap<>();
            appointMap.put(reqMsg.getType(), reqMsg.getPosition());

            //任命开始算钱
            appointUserData.setPosAddSilverTime(System.currentTimeMillis());
            if (titleConfig.getType() == 1) {
                addNeedSyncPosUser(appointUserData);
            }

            // 日志
            ChannelAutoLogMgr.add(new LogChannelTonBingAppoint(
                    config.getActivityInfo().getActivityId(),
                    userId,
                    reqMsg.getUserId(),
                    titleConfig.getId(),
                    winnerUserData.getCampId()
            ));

            //减益buff还要去本服通知扣除他英两的增加
            UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(appointUserData.getUserId());
            UserBaseInfo winnerUserBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
            if (userBaseInfo != null) {
                ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.Builder crespMsg = ChannelTonBingProto.ChannelTonBingCityWinerAppointRespMsg.newBuilder();
                crespMsg.setWinerName(winnerUserBaseInfo == null ? "" : winnerUserBaseInfo.getNickName());
                parsePosAppoint(crespMsg, appointMap);
                crespMsg.setCampId(appointUserData.getCampId());
                crespMsg.setSendReward(true);
                sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_CITY_APPOINT_POSITION, crespMsg, appointUserData);
            } else {
                logger.error("跨域统兵任命找不到任命玩家的userBaseInfo");
            }
            addRedDot(appointUserData, eTonBingRedDotType.Type12_BeAppoint);

            sendChannelPacket(ClientProtocol.U_CTON_BING_CITY_WINNER_APPOINT, respMsg, userData);
        }
    }

    /**
     * 任命指挥官
     */
    public void campCommanderAppoint(long userId, ChannelTonBingProto.ChannelTonBingCampCommanderAppointReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.campCommanderAppoint(userId, reqMsg);
        }
    }

    /**
     * 指挥官设置信息
     */
    public void commanderSet(long userId, ChannelTonBingProto.ChannelTonBingCommanderSetReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.commanderSet(userId, reqMsg);
        }
    }

    /**
     * 获取同阵营的用户数据
     */
    public void getCampUserData(long userId, ChannelTonBingProto.ChannelTonBingCampUserDataReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.getCampUserData(userId, reqMsg);
        }
    }

    public void getUserBarracksInfo(long userId) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.getUserBarracksInfo(userId);
        }
    }

    /**
     * 获取招募所需银两
     */
    public void recruitSoldierSliver(long serverId, long userId, ChannelTonBingProto.ChannelTonBingRecruitSoldierReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.recruitSoldierSliver(serverId, userId, reqMsg);
        }
    }

    /**
     * 招募士兵
     */
    public void recruitSoldier(long serverId, long userId, ChannelTonBingProto.ChannelTonBingRecruitSoldierReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.recruitSoldier(serverId, userId, reqMsg);
        }
    }

    public void changeSoldier(long userId, ChannelTonBingProto.ChannelTonBingChangeTeamSoldierReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.changeSoldier(userId, reqMsg);
        }
    }

    public void makeNpcEvent() {
        for (ChannelTonBingMatch match : matchMap.values()) {
            if (!match.isGameOver()) {
                match.makeNpcEvent();
            }
        }
    }

    //处理事件
    public void dealEvent(long userId, ChannelTonBingProto.ChannelTonBingDealEventReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.dealEvent(userId, reqMsg);
        }
    }

    public void getBattleFieldByCmd(long userId, ChannelTonBingProto.CTonBingGetBattlefieldReqMsg reqMsg) {
        if (watchMap.containsKey(userId)) {
            ChannelTonBingMatch match = getMatchByMatchId(watchMap.get(userId));
            if (match != null) {
                match.getBattleFieldByCmd(getUserData(userId), userId, reqMsg);
            }
        }
    }

    public void getCityDetailByCmd(long userId, ChannelTonBingProto.CTonBingGetCityDetailReqMsg reqMsg) {
        if (watchMap.containsKey(userId)) {
            ChannelTonBingMatch match = getMatchByMatchId(watchMap.get(userId));
            if (match != null) {
                match.getCityDetailByCmd(getUserData(userId), reqMsg);
            }
        }
    }

    public void cityFoodInfo(long userId) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.cityFoodInfo(userId);
        }
    }

    public void cityFoodCollect(long userId) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.cityFoodCollect(userId);
        }
    }


    public void getCityTeamByCmd(long userId, ChannelTonBingProto.CTonBingSyncCityTeamReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.getCityTeamByCmd(userId, reqMsg);
        }
    }

    public void useWarDrumByCmd(long userId, ChannelTonBingProto.ChannelTonBingUseWarDrumReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.useWarDrumByCmd(userId, reqMsg);
        }
    }

    public void needHelpByCmd(long userId, ChannelTonBingProto.CTonBingNeedHelpReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.needHelpByCmd(userId, reqMsg);
        }
    }

    public void getBattlefieldRankByCmd(long userId, ChannelTonBingProto.CTonBingGetBattlefieldRankReqMsg reqMsg) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.getBattlefieldRankByCmd(userId, reqMsg);
        }
    }

    public void sendChatByCmd(long userId, CrossActivityProto.CrossActivityChatReqMsg.Builder reqMsg) {
        int range = 0;
        int id = 0;
        if (eMessageType.TonBingPublicChat.getValue() == reqMsg.getMsg().getType()) {
            range = ChannelTonBingChatLogic.RANGE_ALL;
            id = config.getActivityInfo().getActivityId();
            // 公屏聊天加上阵营
            WorldMessageProto.WorldMessageTempMsg.Builder message = reqMsg.getMsg().toBuilder();
            message.setExtraParams(String.valueOf(getUserCampId(userId)));
            reqMsg.setMsg(message);
        } else if (eMessageType.TonBingCampChat.getValue() == reqMsg.getMsg().getType()) {
            /**/
            int matchId = watchMap.getOrDefault(userId, 0);
            ChannelTonBingMatch match = getMatchByMatchId(matchId);
            if (match != null) {
                match.sendChatByCmd(userId, reqMsg);
                return;
            } else {
                range = ChannelTonBingChatLogic.RANGE_CAMP;
                id = getUserCampId(userId);
            }
        } else if (eMessageType.TonBingBattlefieldChat.getValue() == reqMsg.getMsg().getType()) {
            /*range = ChannelTonBingChatLogic.RANGE_SYSTEM;
            UserScene userScene = CrossSceneMgr.getUserScene(userId);
            if (userScene != null && eSceneType.TonBingBattlefield.getValue() == userScene.getSceneType()) {
                try {
                    String cityIdStr = userScene.getSceneId().split("-")[0];
                    id = Integer.valueOf(cityIdStr);
                } catch (Exception e) {
                }
            }*/
            int matchId = watchMap.getOrDefault(userId, 0);
            ChannelTonBingMatch match = getMatchByMatchId(matchId);
            if (match != null) {
                match.sendChatByCmd(userId, reqMsg);
            }
            return;
        }

        if (range <= 0 || id <= 0) {
            return;
        }

        chatLogic.chat(range, id, 1, reqMsg.getMsg(), 0);
    }

    public void getChatByCmd(long userId, List<Integer> paramList, int param2, int channelId, long userServeId) {
        List<WorldMessageProto.WorldMessageTempMsg> dataList = new ArrayList<>();
        if (paramList.isEmpty()) {
            return;
        }
        for (int range : paramList) {
            int id = 0;
            //这个里面有活动的所有人都能看的聊天已经战场公告，战场公告是要去对应比赛拿的这里不用continue
            if (range == ChannelTonBingChatLogic.RANGE_ALL) {
                int matchId = watchMap.getOrDefault(userId, 0);
                ChannelTonBingMatch match = getMatchByMatchId(matchId);
                if (match != null) {
                    List<WorldMessageProto.WorldMessageTempMsg> adddataList = match.getChatByCmd(getUserData(userId), range, param2);
                    dataList.addAll(adddataList);
                }
                id = config.getActivityInfo().getActivityId();
            } else if (range == ChannelTonBingChatLogic.RANGE_CAMP) {
                ChannelTonBingUserData userData = getUserData(userId);
                if (userData != null) {
                    id = userData.getCampId();
                }
                int matchId = watchMap.getOrDefault(userId, 0);
                ChannelTonBingMatch match = getMatchByMatchId(matchId);
                if (match != null) {
                    List<WorldMessageProto.WorldMessageTempMsg> adddataList = match.getChatByCmd(getUserData(userId), range, param2);
                    dataList.addAll(adddataList);
                    //不用再加下面的了，下面的有不是比赛的阵营聊天
                    continue;
                }
            } else if (range == ChannelTonBingChatLogic.RANGE_BATTLEFIELD) {
                // 城池id
                id = param2;
                int matchId = watchMap.getOrDefault(userId, 0);
                ChannelTonBingMatch match = getMatchByMatchId(matchId);
                if (match != null) {
                    List<WorldMessageProto.WorldMessageTempMsg> adddataList = match.getChatByCmd(getUserData(userId), range, param2);
                    dataList.addAll(adddataList);
                }
            }

            if (range <= 0 || id <= 0) {
                continue;
            }
            dataList.addAll(chatLogic.getChatMsg(range, id));
        }

        CrossActivityProto.CrossActivityChatListRespMsg.Builder respMsg = CrossActivityProto.CrossActivityChatListRespMsg.newBuilder();
        respMsg.setActivityId(config.getActivityInfo().getActivityId());
        if (dataList.size() > 0) {
            dataList.sort(Comparator.comparingLong(WorldMessageProto.WorldMessageTempMsg::getSendTime));
            WorldMessageProto.WorldMessageListMsg.Builder worldMessageListMsg = WorldMessageProto.WorldMessageListMsg.newBuilder();
            worldMessageListMsg.addAllDataList(dataList);
            respMsg.setDataList(worldMessageListMsg);
            ChannelMessageHelper.sendGamePacket(Protocol.U_CROSS_ACTIVITY_CHAT_LIST, respMsg, channelId, userServeId, userId);
        }
    }

    public void getRankRewardByCmd(long userId, ChannelTonBingProto.CTonBingGetRankRewardReqMsg reqMsg) {
        ChannelTonBingUserData userData = getUserData(userId);

        int ret = getRankReward(userId, reqMsg.getConditionType());
        if (ret != 0) {
            ChannelTonBingProto.CTonBingGetRankRewardRespMsg.Builder builder = ChannelTonBingProto.CTonBingGetRankRewardRespMsg.newBuilder();
            builder.setRet(ret);
            sendChannelPacket(ClientProtocol.U_CTON_BING_GET_RANK_REWARD, builder, userData);
        }
    }

    //获取战功和积分的总排名
    private Map<Integer, Map<Integer, Map<Integer, Long>>> getCampValueMap() {
        //matchId 1战功 2积分 campId 值
        Map<Integer, Map<Integer, Map<Integer, Long>>> mmMap = new ConcurrentHashMap<>();
        for (ChannelTonBingMatch match : matchMap.values()) {
            int matchId = match.getChannelTonBingData().getMatchId();
            mmMap.put(matchId, new ConcurrentHashMap<>());
            Map<Integer, Long> campIntegralMap = new ConcurrentHashMap<>();
            for (ChannelTonBingCity city : match.getChannelTonBingData().getCityMap().values()) {
                int campId = city.getCampId();
                int cityId = city.getCityId();
                if (campId == 0) {
                    continue;
                }
                long addIntegral = config.getCityScore(match.getChannelTonBingData().getWarType(), cityId, match.getChannelTonBingData().getTurn());
                long oldIntegral = campIntegralMap.getOrDefault(campId, 0L);
                campIntegralMap.put(campId, oldIntegral + addIntegral);
            }
            mmMap.get(matchId).put(2, campIntegralMap);
            Map<Integer, Long> campZhanGongMap = new ConcurrentHashMap<>();
            for (ChannelTonBingUserData userData : match.getUserDataMap().values()) {
                Map<Integer, Long> zgMap = userData.getZhanGongMap();
                long addZhangong = zgMap.getOrDefault(matchId, 0L);
                long oldZhangong = campZhanGongMap.getOrDefault(userData.getCampId(), 0L);
                campZhanGongMap.put(userData.getCampId(), oldZhangong + addZhangong);
            }
            mmMap.get(matchId).put(1, campZhanGongMap);
        }
        return mmMap;
    }

    //每个比赛战功排名
    private Map<Integer, Map<String, Integer>> getMatchUnionZGRank() {
        Map<Integer, Map<String, Integer>> mUnionZgMap = new ConcurrentHashMap<>();
        for (ChannelTonBingMatch match : matchMap.values()) {
            Map<String, Integer> unionZhanGongRankMap = new ConcurrentHashMap<>();
            LinkedList<ChannelTonBingRank> unionRankList = match.getAllUnionRankMap();
            int rank = 0;
            for (ChannelTonBingRank rankData : unionRankList) {
                rank++;
                unionZhanGongRankMap.put(rankData.getId(), rank);
            }
            mUnionZgMap.put(match.getChannelTonBingData().getMatchId(), unionZhanGongRankMap);
        }
        return mUnionZgMap;
    }

    //每一场中的每一个商会的战功是多少
    private Map<Integer, Map<String, Long>> getUnionZhangongValueMap() {
        //matchId unionId 战功值
        Map<Integer, Map<String, Long>> mmMap = new ConcurrentHashMap<>();
        for (ChannelTonBingMatch match : matchMap.values()) {
            int matchId = match.getChannelTonBingData().getMatchId();
            Map<String, Long> unionZhanGongMap = new ConcurrentHashMap<>();
            for (ChannelTonBingUserData userData : match.getUserDataMap().values()) {
                Map<Integer, Long> zgMap = userData.getZhanGongMap();
                long addZhangong = zgMap.getOrDefault(matchId, 0L);
                long oldZhangong = unionZhanGongMap.getOrDefault(userData.getUnionUid(), 0L);
                unionZhanGongMap.put(userData.getUnionUid(), oldZhangong + addZhangong);
            }
            mmMap.put(matchId, unionZhanGongMap);
        }
        return mmMap;
    }

    //每一场比赛的每个阵营的战功排行
    private Map<Integer, Map<Integer, Integer>> getUnionZhangongRankMap() {
        //matchId unionId 战功值
        Map<Integer, Map<Integer, Integer>> resMap = new ConcurrentHashMap<>();
        Map<Integer, Map<Integer, Map<Integer, Long>>> mmMap = getCampValueMap();
        for (int matchId : mmMap.keySet()) {
            List<ChannelTonBingRank> rankList = new ArrayList<>();
            Map<Integer, Long> campIdZhangongMap = new ConcurrentHashMap<>();
            Map<Integer, Long> intMap = mmMap.get(matchId).get(1);//战功
            for (int cId : intMap.keySet()) {
                campIdZhangongMap.put(cId, intMap.getOrDefault(cId, 0L));
            }
            if (campIdZhangongMap.size() > 0) {
                for (int campId : campIdZhangongMap.keySet()) {
                    ChannelTonBingRank rank = new ChannelTonBingRank();
                    rank.setId(campId + "");
                    rank.setValue(campIdZhangongMap.get(campId));
                    rankList.add(rank);
                }
                Map<Integer, Integer> unionZhanGongRankMap = new ConcurrentHashMap<>();
                rankList.sort(new GroupRankSort());
                int rank = 1;
                for (ChannelTonBingRank rankInfo : rankList) {
                    unionZhanGongRankMap.put(Integer.valueOf(rankInfo.getId()), rank);
                    rank++;
                }
                resMap.put(matchId, unionZhanGongRankMap);
            }
        }
        return resMap;
    }

    public void getCampRankListByCmd(long userId, int channelId, long serverId) {
        ChannelTonBingProto.CTonBingGetCampRankRespMsg.Builder builder = ChannelTonBingProto.CTonBingGetCampRankRespMsg.newBuilder();
        builder.setRet(0);
        Map<Integer, Map<Integer, Map<Integer, Long>>> mmMap = getCampValueMap();
        //不知道阵营排行榜是所有的还是对应每一个战场
        for (ChannelTonBingRank rank : getCampScoreRankList()) {
            ChannelTonBingProto.CTonBingCampRankMsg.Builder rankMsg = parseTonBingCampRankMsg(rank);
            int campId = rankMsg.getCampId();
            for (int matchId : mmMap.keySet()) {
                ChannelTonBingMatch match = matchMap.get(matchId);
                Map<Integer, Map<Integer, Long>> ccMap = mmMap.get(matchId);
                Map<Integer, Long> zgMap = ccMap.get(1);
                Map<Integer, Long> intMap = ccMap.get(2);
                ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.Builder matchRankMsg = ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.newBuilder();
                matchRankMsg.setTurn(match.getChannelTonBingData().getTurn());
                matchRankMsg.setMatchId(match.getChannelTonBingData().getMatchId());
                matchRankMsg.setWarType(match.getChannelTonBingData().getWarType());
                matchRankMsg.setIntegral(intMap.getOrDefault(campId, 0L));
                matchRankMsg.setZhangong(zgMap.getOrDefault(campId, 0L));
                rankMsg.addMatchInfo(matchRankMsg);
            }
            builder.addRank(rankMsg);
        }
        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_GET_CAMP_RANK_LIST, builder, channelId, serverId, userId);
    }

    private ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.Builder parseTonBingCampUnionMatchRankMsg(ChannelTonBingMatch match, Map<Integer, Map<Integer, Long>> ccMap) {
        Map<Integer, Long> zgMap = ccMap.get(1);
        Map<Integer, Long> intMap = ccMap.get(2);
        ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.Builder matchRankMsg = ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.newBuilder();
        matchRankMsg.setTurn(match.getChannelTonBingData().getTurn());
        matchRankMsg.setMatchId(match.getChannelTonBingData().getMatchId());
        matchRankMsg.setWarType(match.getChannelTonBingData().getWarType());
//        matchRankMsg.setIntegral(intMap.getOrDefault(campId,0L));
//        matchRankMsg.setZhangong(zgMap.getOrDefault(campId,0L));
        return matchRankMsg;
    }

    public void getMatchCampUnionRankListByCmd(long userId, ChannelTonBingProto.CTonBingGetCampUnionRankReqMsg reqMsg, int channelId, long serverId) {
        if (reqMsg.getMatchId() == 0) {
            getCampUnionRankListByCmd(userId, reqMsg, channelId, serverId);
        } else {
            ChannelTonBingMatch match = getMatchByMatchId(reqMsg.getMatchId());
            if (match != null) {
                match.getCampUnionRankListByCmd(userId, reqMsg);
            }
        }
    }

    //获取当前商会的战场
    private int getNowWarType(String unionId) {
        int nowTurn = config.getTurn();
        if (System.currentTimeMillis() > config.getActivityInfo().getEndTime() * 1000) {
            nowTurn = config.getLastTurn();
        }
        if (turnMatchMap.containsKey(nowTurn)) {
            for (Map<Integer, ChannelTonBingMatch> matchMap : new ConcurrentHashMap<>(turnMatchMap.get(nowTurn)).values()) {
                for (ChannelTonBingMatch match : matchMap.values()) {
                    if (match.getUnionJoin(unionId) != null) {
                        return match.getChannelTonBingData().getWarType();
                    }
                }
            }
        }
        return 0;
    }

    public void getCampUnionRankListByCmd(long userId, ChannelTonBingProto.CTonBingGetCampUnionRankReqMsg reqMsg, int channelId, long serverId) {
        int campId = reqMsg.getCampId();
        ChannelTonBingUserData userData = getUserData(userId);
        String unionUid = userData == null ? "" : userData.getUnionUid();

        ChannelTonBingProto.CTonBingGetCampUnionRankRespMsg.Builder builder = ChannelTonBingProto.CTonBingGetCampUnionRankRespMsg.newBuilder();
        builder.setRet(0);
        List<ChannelTonBingRank> rankList = new ArrayList<>();
        if (campId == 0) {
            // 获取全部商会
            for (ChannelTonBingRankListModel model : campUnionRankMap.values()) {
                if (model != null) {
                    rankList.addAll(model.getRankList());
                }
            }
        } else {
            ChannelTonBingRankListModel model = campUnionRankMap.get(campId);
            if (model != null) {
                rankList.addAll(model.getRankList());
            }
        }
        for (ChannelTonBingRank rank : rankList) {
            ChannelTonBingUnionJoin unionJoin = getUnionJoin(rank.getId());
            rank.setWarType(getNowWarType(rank.getId()));
            rank.setAbility(unionJoin.getTotalAbility());
        }
        rankList.sort(new ChannelTonBingRankSort());

        int rankShowLimit = unionMaxRankConfig;
        if (campId == 0) {
            rankShowLimit = unionMaxRankConfig * config.getCampNum();
        }
        // 获取商会排名
        int num = 0;
        Map<Integer, Map<String, Long>> mmMap = getUnionZhangongValueMap();
        Map<Integer, Map<Integer, Integer>> rankMap = getUnionZhangongRankMap();
        Map<Integer, Map<String, Integer>> unionZgRankMap = getMatchUnionZGRank();
        for (ChannelTonBingRank rank : rankList) {
            num++;
            if (num > rankShowLimit) {
                break;
            }
            builder.addRank(parseTonBingCampUnionRankMsg(rank, getNowWarType(rank.getId()), mmMap, rankMap, unionZgRankMap));
        }

        // 获取商会阵营排名
        int myRank = -1;
        int myCampId = userData == null ? 0 : userData.getCampId();
        if (myCampId != 0) {
            ChannelTonBingRankListModel model = campUnionRankMap.get(myCampId);
            if (model != null) {
                int cnt = 0;
                for (ChannelTonBingRank rank : model.getRankList()) {
                    cnt++;
                    if (cnt > rankShowLimit) {
                        break;
                    }
                    if (Objects.equals(rank.getId(), unionUid)) {
                        myRank = cnt;
                    }
                }
            }
        }
        builder.setMyRank(myRank);

        long myValue = 0L;
        ChannelTonBingUnionJoin unionJoin = getUnionJoin(unionUid);
        if (unionJoin != null) {
            for (ChannelTonBingUnionJoinMember member : unionJoin.getMemberMap().values()) {
                ChannelTonBingUserData tmp = getUserData(member.getUserId());
                myValue += tmp.getZhanGong();
            }
        }
        builder.setMyValue(myValue);

        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_GET_CAMP_UNION_RANK_LIST, builder, channelId, serverId, userId);
    }

    public void getUserRankListByCmd(long userId, ChannelTonBingProto.CTonBingGetUserRankReqMsg reqMsg, int channelId, long serverId) {
        int type = reqMsg.getType();
        ChannelTonBingUserData userData = getUserData(userId);
        long myValue = userData == null ? 0 : userData.getZhanGong();
        String myId = String.valueOf(userId);
        LinkedList<ChannelTonBingRank> rankList;
        int maxRank = 100;

        // 【查其他玩家排名】
        if (type == 3) {
            getOtherUserRankByCmd(userId, reqMsg.getParam(), channelId, serverId);
            return; // ！！！
        }

        if (type == 1) {
            // 【个人榜】
            rankList = userRank.getRankList();
            maxRank = userMaxRankConfig;
        } else if (type == 2) {
            // 【商会内个人榜】
            String unionUid = reqMsg.getParam();
            ChannelTonBingUnionJoin unionJoin = getUnionJoin(unionUid);
            if (StringUtils.isNullOrEmpty(unionUid) || unionJoin == null) {
                return; // 参数错误
            }
            // 组装个榜单
            ChannelTonBingRankListModel tmpModel = new ChannelTonBingRankListModel();
            LinkedList<ChannelTonBingRank> tmpList = new LinkedList<>();
            for (Long memberId : unionJoin.getMemberMap().keySet()) {
                ChannelTonBingUserData member = getUserData(memberId);
                tmpList.add(new ChannelTonBingRank(String.valueOf(member.getUserId()), member.getZhanGong(), member.getZhanGongTime()));
            }
            tmpModel.setRankList(tmpList); // 排序
            rankList = tmpModel.getRankList();
        } else if (reqMsg.getType() == 4) {
            // 【商会内个人今天榜】
            String unionUid = reqMsg.getParam();
            ChannelTonBingUnionJoin unionJoin = getUnionJoin(unionUid);
            ChannelTonBingMatch match = getMatchByUnionId(unionUid);
            if (StringUtils.isNullOrEmpty(unionUid) || unionJoin == null || match == null) {
                return; // 参数错误
            }
            // 组装个榜单
            ChannelTonBingRankListModel tmpModel = new ChannelTonBingRankListModel();
            LinkedList<ChannelTonBingRank> tmpList = new LinkedList<>();
            for (Long memberId : unionJoin.getMemberMap().keySet()) {
                ChannelTonBingUserData member = getUserData(memberId);
                tmpList.add(new ChannelTonBingRank(String.valueOf(member.getUserId()), member.getZhanGongMap().getOrDefault(match.getChannelTonBingData().getMatchId(), 0L), member.getZhanGongTime()));
            }
            tmpModel.setRankList(tmpList); // 排序
            rankList = tmpModel.getRankList();
        } else {
            return; // 参数错误
        }

        ChannelTonBingProto.CTonBingGetUserRankRespMsg.Builder builder = ChannelTonBingProto.CTonBingGetUserRankRespMsg.newBuilder();
        builder.setRet(0);

        int myRank = -1;
        int rankNum = 0;
        int beginRank = 0;
        int endRank = 0;
        if (type == 1 && reqMsg.hasPageNo()) {
            beginRank = Math.max(reqMsg.getPageNo() * reqMsg.getPageSize() + 1, 1);
            endRank = Math.min(beginRank + reqMsg.getPageSize() - 1, maxRank);
        }

        for (ChannelTonBingRank rank : rankList) {
            rankNum++;
            if (rankNum > maxRank) {
                break;
            }
            if (Objects.equals(rank.getId(), myId)) {
                myRank = rankNum;
            }

            if (type == 1 && reqMsg.hasPageNo()) {
                if (rankNum >= beginRank && rankNum <= endRank) {
                    builder.addRank(parseTonBingUserRankMsg(rank));
                }
            } else {
                builder.addRank(parseTonBingUserRankMsg(rank));
            }
        }

        builder.setMyRank(myRank);
        builder.setMyValue(myValue);
        if (reqMsg.hasPageNo() && reqMsg.hasPageSize()) {
            builder.setPageNo(reqMsg.getPageNo());
            builder.setPageSize(reqMsg.getPageSize());
        }

        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_GET_USER_RANK_LIST, builder, channelId, serverId, userId);
    }

    public void getOtherUserRankByCmd(long userId, String otherUserId, int channelId, long serverId) {
        int otherRank = -1;
        long otherValue = 0L;

        int num = 0;
        for (ChannelTonBingRank rank : userRank.getRankList()) {
            num++;
            if (num > userMaxRankConfig) {
                break;
            }
            if (Objects.equals(rank.getId(), otherUserId)) {
                otherRank = num;
                otherValue = rank.getValue();
                break;
            }
        }

        ChannelTonBingProto.CTonBingGetUserRankRespMsg.Builder builder = ChannelTonBingProto.CTonBingGetUserRankRespMsg.newBuilder();
        builder.setRet(0);
        builder.setMyRank(otherRank);
        builder.setMyValue(otherValue);
        // builder.setRank(); // 传排名，不需要传rankList
        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_GET_USER_RANK_LIST, builder, channelId, serverId, userId);
    }

    public void readRedDotByCmd(long userId, ChannelTonBingProto.CTonBingReadRedDotReqMsg reqMsg) {
        ChannelTonBingUserData userData = getUserData(userId);
        if (isAble(userData)) {
            userData.getRedDotMap().remove(reqMsg.getType());
            userData.setUpdateOption();
        }
    }

    //+++pb+++//
    public ChannelTonBingProto.CTonBingCampRankMsg.Builder parseTonBingCampRankMsg(ChannelTonBingRank rank) {
        Integer campId = Integer.valueOf(rank.getId());

        // 拿一下阵营第一的昵称
        UserBaseInfo userBaseInfo = getCampMaxZhanGongUserBaseInfo(campId);
        String nickname = userBaseInfo == null ? "" : userBaseInfo.getNickName();

        ChannelTonBingProto.CTonBingCampRankMsg.Builder builder = ChannelTonBingProto.CTonBingCampRankMsg.newBuilder();
        builder.setCampId(campId);
        builder.setValue(rank.getValue());
        builder.setMaxNickname(nickname);
        return builder;
    }

    //用matchId获得是第几轮的什么战场的第几组
    private int getMatchIdTurn(int matchId) {
        ChannelTonBingMatch match = getMatchByMatchId(matchId);
        if (match == null) {
            return 0;
        }
        Map<Integer, Map<Integer, ChannelTonBingMatch>> warTypeMap = turnMatchMap.get(match.getChannelTonBingData().getTurn());
        if (warTypeMap == null) {
            return 0;
        }
        Map<Integer, ChannelTonBingMatch> matchMap = warTypeMap.get(match.getChannelTonBingData().getWarType());
        if (matchMap == null) {
            return 0;
        }
        List<Integer> matchIdList = new ArrayList<>(matchMap.keySet());
        Collections.sort(matchIdList);
        return matchIdList.indexOf(matchId) + 1;
    }

    public ChannelTonBingProto.CTonBingCampUnionRankMsg.Builder parseTonBingCampUnionRankMsg(ChannelTonBingRank rank, int warType, Map<Integer, Map<String, Long>> mmMap, Map<Integer, Map<Integer, Integer>> rankMap, Map<Integer, Map<String, Integer>> unionZgRankMap) {
        String unionUid = rank.getId();
        ChannelTonBingUnionJoin channelTonBingUnionJoin = unionJoinMap.get(unionUid);
        UnionBaseInfo unionBaseInfo = channelTonBingUnionJoin == null ? new UnionBaseInfo() : channelTonBingUnionJoin.getUnionBaseInfo();
        ChannelTonBingProto.CTonBingCampUnionRankMsg.Builder builder = ChannelTonBingProto.CTonBingCampUnionRankMsg.newBuilder();
        builder.setUnionUid(unionUid);
        builder.setValue(rank.getValue());
        builder.setUnionInfo(UnionBasePb.parseUnionBaseTempMsg(unionBaseInfo));
        builder.setCampId(channelTonBingUnionJoin == null ? 0 : channelTonBingUnionJoin.getCampId());
        ChannelTonBingUnionJoin join = getUnionJoin(unionUid);
        for (int matchId : mmMap.keySet()) {
            ChannelTonBingMatch match = matchMap.get(matchId);
            //判断这场比赛是不是有这个商会
            ChannelTonBingUnionJoin matchJoin = match.getUnionJoin(unionUid);
            if (matchJoin == null) continue;
            if (!config.isRankStartTime(match.getChannelTonBingData().getTurn())) {
                continue;
            }
            Map<String, Long> ccMap = mmMap.get(matchId);
            ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.Builder matchRankMsg = ChannelTonBingProto.CTonBingCampUnionMatchRankMsg.newBuilder();
            matchRankMsg.setTurn(match.getChannelTonBingData().getTurn());
            matchRankMsg.setMatchId(getMatchIdTurn(match.getChannelTonBingData().getMatchId()));
            matchRankMsg.setWarType(match.getChannelTonBingData().getWarType());
            matchRankMsg.setIntegral(0);
            matchRankMsg.setZhangong(ccMap.getOrDefault(join.getUnionUid(), 0L));
//            matchRankMsg.setUnionZhangongRank(rankMap.get(matchId).getOrDefault(join.getCampId(),0));
            matchRankMsg.setUnionZhangongRank(unionZgRankMap.get(matchId).getOrDefault(join.getUnionUid(), 0));
            builder.addMatchInfo(matchRankMsg);
        }
        builder.setWarType(warType);

        return builder;
    }

    public ChannelTonBingProto.CTonBingUserRankMsg.Builder parseTonBingUserRankMsg(ChannelTonBingRank rank) {
        Long userId = Long.valueOf(rank.getId());
        UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }
        ChannelTonBingUserData userData = getUserData(userId);
        int campId = userData.getCampId();

        ChannelTonBingProto.CTonBingUserRankMsg.Builder builder = ChannelTonBingProto.CTonBingUserRankMsg.newBuilder();
        builder.setUserId(userId);
        builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setValue(rank.getValue());
        builder.setCampId(campId);
        for (int matchId : userData.getZhanGongMap().keySet()) {
            ChannelTonBingMatch match = getMatchByMatchId(matchId);
            if (match != null) {
                if (!config.isRankStartTime(match.getChannelTonBingData().getTurn())) {
                    continue;
                }
                ChannelTonBingProto.CTonBingUserMatchInfoMsg.Builder matchInfoMsg = ChannelTonBingProto.CTonBingUserMatchInfoMsg.newBuilder();
                matchInfoMsg.setWarType(match.getChannelTonBingData().getWarType());
                matchInfoMsg.setTurn(match.getChannelTonBingData().getTurn());
                matchInfoMsg.setZhangong(userData.getZhanGongMap().get(matchId));
                builder.addMatchInfo(matchInfoMsg);
            }
        }

        return builder;
    }

    public ChannelTonBingProto.CTonBingRedPacketMsg.Builder parseTonBingRedPacketMsg(ChannelTonBingRedPacket redPacket, boolean getReward) {
        UserBaseInfo userBaseInfo = ChannelUserMgr.getUserBaseInfo(redPacket.getUserId());
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }

        ChannelTonBingProto.CTonBingRedPacketMsg.Builder tempMsg = ChannelTonBingProto.CTonBingRedPacketMsg.newBuilder();
        tempMsg.setUserId(redPacket.getUserId());
        tempMsg.setNickName(userBaseInfo.getNickName());
        tempMsg.setUnionName(userBaseInfo.getUnionName());
        tempMsg.setType(redPacket.getGoodId());
        tempMsg.setOrderNo("" + redPacket.getRedPacketNo());
        tempMsg.setIsGet(getReward ? 1 : 0);
        return tempMsg;
    }

    // ============================== SYNC ==============================

    public void syncBaseDataMsg(ChannelTonBingUserData userData) {
        if (userData == null) {
            return;
        }

        int joinStatus = 0; // 0未报名、1已报名、2有资格、3商会未入选
        if (getChannelTonBingDataMain().isLockUnion()) {
            joinStatus = isAble(userData) ? 2 : 3;
        } else {
            for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
                if (join.getMemberMap().containsKey(userData.getUserId())) {
                    joinStatus = 1;
                    break;
                }
            }
        }

        ChannelTonBingProto.CTonBingSyncBaseDataRespMsg.Builder builder = ChannelTonBingProto.CTonBingSyncBaseDataRespMsg.newBuilder();
        builder.setJoinStatus(joinStatus);
        if (userData.getCampId() != 0) {
            builder.setCampId(userData.getCampId());
        }
        builder.setSyncPatronsTime(userData.getLastSyncPatronsTime());
        builder.setGuide(userData.getGuide());
        builder.setSyncNeedHelpTime(userData.getNeedHelpTime());
        builder.setHavePatrons(!userData.getPatronsMap().isEmpty());
        sendChannelPacket(GameProtocol.S_CTON_BING_SYNC_BASE_DATA, builder, userData);
    }

    /**
     * 跨服同步用户数据到游戏服
     */
    public void syncUserDataToGameServer(ChannelTonBingUserData userData, boolean sendPatrons) {
        if (userData == null) {
            return;
        }
        ChannelTonBingProto.ChannelTonBingSyncUserDataMsg.Builder builder = ChannelTonBingProto.ChannelTonBingSyncUserDataMsg.newBuilder();
        builder.setCampId(userData.getCampId());
        builder.setZhanGong(userData.getZhanGong());
        builder.setSendLogin(sendPatrons);
        sendChannelPacket(GameProtocol.S_CHANNEL_CTON_BING_SYNC_USER_DATA, builder, userData);
    }

    /**
     * 同步发光数据
     */
    private void syncLight(long userId, int channelId, long serverId) {
        long currentSecond = DateHelper.getCurrentTime() / 1000;
        if (currentSecond >= getConfig().getActivityInfo().getEndTime()) {
            return;//活动结束不同步
        }

        List<Long> userIdList = new ArrayList<>();
        for (ChannelTonBingRank rank : userRank.getRankList()) {
            if (userIdList.size() >= config.getLightRankNum() || rank.getValue() < config.getLightNeedZhanGong()) {
                break;
            }
            userIdList.add(Long.valueOf(rank.getId()));
        }

        if (userIdList.isEmpty()) {
            return;
        }

        ChannelTonBingProto.CTonBingSyncLightUserRespMsg.Builder builder = ChannelTonBingProto.CTonBingSyncLightUserRespMsg.newBuilder();
        builder.addAllUserId(userIdList);
        ChannelMessageHelper.sendGamePacket(ClientProtocol.U_CTON_BING_SYNC_LIGHT_USER, builder, channelId, serverId, userId);
    }


    // ============================== 聊天 ==============================
    public void syncChat(int range, int id, WorldMessageProto.WorldMessageTempMsg chatMsg, int matchId) {
        long now = System.currentTimeMillis();
        List<Long> userIdList = new ArrayList<>();
        if (range == ChannelTonBingChatLogic.RANGE_ALL) {
            if (matchId != 0) {
                ChannelTonBingMatch match = getMatchByMatchId(matchId);
                if (match != null) {
                    match.syncChat(range, id, chatMsg, matchId);
                }
                return;
            }
            // 所有人都要接收，所以换个发包方式
            for (int channelId : channelIdList) {
                for (long serverId : config.getActivityInfo().getServerIdList()) {
                    if (ChannelActivityUnionMgr.isServerIdInChannel(serverId, channelId)) {
                        sendChannelPacket(Protocol.A_WORLD_MESSAGE_TRANSFER, chatMsg.toBuilder(), serverId, channelId);
                    }
                }
            }
            return;
        } else if (range == ChannelTonBingChatLogic.RANGE_CAMP) {
            if (matchId != 0) {
                ChannelTonBingMatch match = getMatchByMatchId(matchId);
                if (match != null) {
                    match.syncChat(range, id, chatMsg, matchId);
                }
                return;
            } else {
                //外部的阵营聊天变成外部的独立，只同步不在战场的囧
                List<Long> syncUserIdList = new ArrayList<>();
                for (ChannelTonBingUserData userData : userDataMap.values()) {
                    if (userData.getCampId() == id) {
                        syncUserIdList.add(userData.getUserId());
                    }
                }
                syncUserIdList.removeAll(watchMap.keySet());
                sendChannelPacketToAll(ClientProtocol.U_WORLD_MESSAGE_SYNC, chatMsg.toBuilder(), syncUserIdList);
                return;
//                userIdList = userDataMap.values().stream().filter(item -> item.getCampId() == id && isInActivity(item, now)).mapToLong(item -> item.getUserId()).boxed().collect(Collectors.toList());
            }
        } else if (range == ChannelTonBingChatLogic.RANGE_BATTLEFIELD) {
//            ChannelTonBingMatch match = getMatchByUserId(chatMsg.getUserId());
            //??????
            ChannelTonBingMatch match = getMatchByMatchId(matchId);
            if (match != null) {
                ChannelTonBingBattlefield battlefield = match.getChannelTonBingData().getCityMap().get(id).getBattlefield();
                if (battlefield != null) {
                    for (Integer partId : battlefield.getPartMap().keySet()) {
                        List<Long> list = ChannelSceneMgr.getSceneUserList(config.getActivityInfo().getActivityId(),
                                        eSceneType.TonBingBattlefield.getValue(),
                                        match.getChannelTonBingData().getMatchId() + "-" + getBattlefieldSceneKey(id, partId),
                                        23333)
                                .stream().mapToLong(item -> item.getUserId()).boxed().collect(Collectors.toList());
                        userIdList.addAll(list);
                    }
                }
            }
        }
        if (!userIdList.isEmpty()) {
            sendChannelPacketToAll(ClientProtocol.U_WORLD_MESSAGE_SYNC, chatMsg.toBuilder(), userIdList);
        }
    }

    // ============================== 其他 ==============================

    public void save() {
        for (ChannelTonBingMatch match : matchMap.values()) {
            match.save();
        }

        if (channelTonBingDataMain.isInsertOption()) {
            ChannelTonBingActivityBusiness.addChannelTonBingDataMain(channelTonBingDataMain);
        } else if (channelTonBingDataMain.isUpdateOption()) {
            ChannelTonBingActivityBusiness.updateChannelTonBingDataMain(channelTonBingDataMain);
        }

        for (ChannelTonBingUnionJoin join : unionJoinMap.values()) {
            if (join.isInsertOption()) {
                ChannelTonBingActivityBusiness.addChannelTonBingUnionJoin(join);
            } else if (join.isUpdateOption()) {
                ChannelTonBingActivityBusiness.updateChannelTonBingUnionJoin(join);
            }
        }

        for (ChannelTonBingUserData data : userDataMap.values()) {
            if (data.isInsertOption()) {
                ChannelTonBingActivityBusiness.addChannelTonBingUserData(data);
            } else if (data.isUpdateOption()) {
                ChannelTonBingActivityBusiness.updateChannelTonBingUserData(data);
            }
        }

        for (ChannelTonBingCampData campData : campDataMap.values()) {
            if (campData.isInsertOption()) {
                ChannelTonBingActivityBusiness.addChannelTonBingCampData(campData);
            } else if (campData.isUpdateOption()) {
                ChannelTonBingActivityBusiness.updateChannelTonBingCampData(campData);
            }
        }

    }

    /**
     * 玩家是否在界面内
     */
    public boolean isInActivity(ChannelTonBingUserData data, long now) {
        if (!isAble(data)) {
            return false; // 无资格的都进不了界面
        }
        if (now - data.getLastReqTime() < DateHelper.MINUTE_MILLIONS * 3) {
            return true; // 3分钟内有请求的都当他在线
        }
        return false;
    }

    /**
     * 设置请求时间
     */
    public void setLastReqTime(long userId) {
        if (userId <= 0) {
            return;
        }
        ChannelTonBingUserData userData = getUserData(userId);
        if (userData == null) {
            return;
        }
        userData.setLastReqTime(System.currentTimeMillis());
    }

    public void printTask() {
        Map<String, Integer> countMap = new ConcurrentHashMap<>();
        for (BaseChannelTonBingActivityTask task : taskQueue) {
            countMap.put(task.getType().name(), countMap.getOrDefault(task.getType().name(), 0) + 1);
        }
        for (ChannelTonBingMatch match : matchMap.values()) {
            if (!match.isGameOver()) {
                match.printTask();
            }
        }

        logger.info("【统兵演武任务】 - {}", JSON.toJSONString(countMap));
    }

    public String getBattlefieldSceneKey(int cityId, int partId) {
        return cityId + "-" + partId;
    }

    public String getTeamKey(ChannelTonBingTeam team) {
        return team.getUserId() + "-" + team.getOccupation();
    }

    public String getTeamKey(ChannelTonBingTeamArrive arrive) {
        return arrive.getUserId() + "-" + arrive.getTeamId();
    }

    public ChannelTonBingTeam getTeamByKey(String key) {
        String[] split = key.split("-");
        ChannelTonBingUserData userData = getUserData(Long.valueOf(split[0]));
        return userData.getTeamMap().get(Integer.valueOf(split[1]));
    }

    public List<Long> getBattlefieldUserIdList(int cityId, int partId) {
        String sceneKey = getBattlefieldSceneKey(cityId, partId);
        List<UserScene> sceneUserList = ChannelSceneMgr.getSceneUserList(
                config.getActivityInfo().getActivityId(),
                eSceneType.TonBingBattlefield.getValue(),
                sceneKey,
                23333);
        return sceneUserList.stream().mapToLong(UserScene::getUserId).boxed().collect(Collectors.toList());
    }

    /**
     * 领取榜单奖励
     */
    private int getRankReward(long userId, int conditionType) {
        ChannelTonBingUserData userData = getUserData(userId);

        // 资格
        if (!isAble(userData)) {
            return GameErrorCode.E_TON_BING_NO_ABLE;
        }

        // 拿职位参数
        ChannelTonBingUnionJoin join = unionJoinMap.get(userData.getUnionUid());
        ChannelTonBingUnionJoinMember member = join.getMemberMap().get(userId);
        int position = member.getPosition();

        // 拿阵营排名参数
        LinkedList<ChannelTonBingRank> campRankList = getCampScoreRankList();
        String myCampId = String.valueOf(userData.getCampId());
        int myCampRank = -1;
        int campRankNum = 0;
        for (ChannelTonBingRank rank : campRankList) {
            campRankNum++;
            if (Objects.equals(rank.getId(), myCampId)) {
                myCampRank = campRankNum;
                break;
            }
        }

        // 拿榜单
        String myId;
        LinkedList<ChannelTonBingRank> rankList;
        if (conditionType == eGamePlayerEventType.TonBingUserZhanGongRank.getValue()) {
            rankList = userRank.getRankList();
            myId = String.valueOf(userId);
        } else if (conditionType == eGamePlayerEventType.TonBingCampUnionZhanGongRank.getValue()) {
            ChannelTonBingRankListModel unionRank = campUnionRankMap.get(userData.getCampId());
            rankList = unionRank == null ? new LinkedList<>() : unionRank.getRankList();
            myId = userData.getUnionUid();
        } else if (conditionType == eGamePlayerEventType.TonBingCampScoreRank.getValue()) {
            rankList = campRankList;
            myId = String.valueOf(userData.getCampId());
        } else {
            return GameErrorCode.E_TON_BING_PARAM_ERR;
        }

        // 【拿榜单排名】
        int myRank = -1;
        int num = 0;
        for (ChannelTonBingRank rank : rankList) {
            num++;
            if (Objects.equals(rank.getId(), myId)) {
                myRank = num;
                break;
            }
        }

        ChannelTonBingProto.ChannelTonBingGetRankRewardRespMsg.Builder builder = ChannelTonBingProto.ChannelTonBingGetRankRewardRespMsg.newBuilder();
        builder.setRet(0);
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setConditionType(conditionType);
        builder.setPosition(position);
        builder.setRank(myRank);
        builder.setCampRank(myCampRank);
        builder.setUnionId(myId);
        sendChannelPacket(GameProtocol.S_CTON_BING_GET_RANK_REWARD_FROM_CHANNEL, builder, userData);
        return 0;
    }

    /**
     * 阵营积分榜单 变成好多个赛区一起加起来，包括历史的结束的
     */
    public LinkedList<ChannelTonBingRank> getCampScoreRankList() {
        Map<Integer, Long> campScoreMap = new ConcurrentHashMap<>();
        Map<Integer, Long> campZhangongMap = new ConcurrentHashMap<>();
        for (ChannelTonBingUserData userData : userDataMap.values()) {
            long oldValue = campZhangongMap.getOrDefault(userData.getCampId(), 0L);
            campZhangongMap.put(userData.getCampId(), oldValue + userData.getZhanGong());
        }
        Map<Integer, Long> updateTimeMap = new ConcurrentHashMap<>();
        LinkedList<ChannelTonBingRank> rankList = new LinkedList<>();
        for (ChannelTonBingMatch match : matchMap.values()) {
            for (ChannelTonBingCity city : match.getChannelTonBingData().getCityMap().values()) {
                int campId = city.getCampId();
                int cityId = city.getCityId();

                if (campId == 0) {
                    continue;
                }

                // 统计积分
//                int cityType = config.getCityConfigMap().get(cityId).getType();
//                long addScore = config.getCityTypeConfigMap().get(cityType).getCampPoint();
                long addScore = config.getCityScore(match.getChannelTonBingData().getWarType(), cityId, match.getChannelTonBingData().getTurn());
                long oldScore = campScoreMap.getOrDefault(campId, 0L);
                campScoreMap.put(campId, oldScore + addScore);
                // 存一下时间
                if (city.getOccupyTime() > updateTimeMap.getOrDefault(campId, 0L)) {
                    updateTimeMap.put(campId, city.getOccupyTime());
                }
            }
        }
        for (Map.Entry<Integer, Long> entry : campScoreMap.entrySet()) {
            int campId = entry.getKey();
            String id = String.valueOf(campId);
            ChannelTonBingRank rank = new ChannelTonBingRank(id, entry.getValue(), updateTimeMap.getOrDefault(entry.getKey(), System.currentTimeMillis()));
            rank.setZhangong(campZhangongMap.getOrDefault(campId, 0L));
            rankList.add(rank);
        }
        ChannelTonBingRankListModel model = new ChannelTonBingRankListModel();
        model.setRankCampList(rankList);
        return model.getRankList();
    }

    /**
     * 通知游戏服condition更新值
     */
    private void notifyConditionChange(long userId, eGamePlayerEventType type, long value) {
        if (type != eGamePlayerEventType.TonBingZhanGong) {
            return;
        }

        ChannelTonBingProto.ChannelTonBingNotifyConditionRespMsg.Builder builder = ChannelTonBingProto.ChannelTonBingNotifyConditionRespMsg.newBuilder();
        builder.setUserId(userId);
        builder.setConditionType(type.getValue());
        builder.setValue(value);
        sendChannelPacket(GameProtocol.S_CTON_BING_NOTIFY_CONDITION_FROM_CHANNEL, builder, getUserData(userId));
    }

    public ChannelTonBingRankListModel getUserRank() {
        return userRank;
    }

    public Map<Integer, ChannelTonBingRankListModel> getCampUnionRankMap() {
        return campUnionRankMap;
    }

    public Map<String, ChannelTonBingUnionJoin> getUnionJoinMap() {
        return unionJoinMap;
    }

    public void changeHorse(long userId, int horseId) {
        ChannelTonBingMatch match = getMatchByUserId(userId);
        if (match != null) {
            match.changeHorse(userId, horseId);
        }
    }

    public void clearChat() {
        logger.error("活动{},清空聊天", config.getActivityInfo().getActivityId());
        chatLogic.clearChat();
        for (int matchId : matchMap.keySet()) {
            ChannelTonBingMatch match = matchMap.get(matchId);
            logger.error("活动{},比赛{},清空聊天", config.getActivityInfo().getActivityId(), matchId);
            match.clearChat();
        }
    }

    /**
     * 邮件补发辎重
     */
    public void mailSendCityCollect() {
        for (ChannelTonBingMatch match : matchMap.values()) {
            if (!match.isGameOver()) {
                match.mailSendCityCollect();
            }
        }
    }

    /**
     * 获取阵营最高战功的玩家
     */
    private UserBaseInfo getCampMaxZhanGongUserBaseInfo(int campId) {
        long userId = getCampMaxZhanGongUserId(campId);
        return userId == 0 ? null : ChannelUserMgr.getUserBaseInfo(userId);
    }

    /**
     * 获取阵营最高战功的玩家Id
     */
    private long getCampMaxZhanGongUserId(int campId) {
        long userId = 0;
        ChannelTonBingRankListModel rankListModel = campUserRankMap.get(campId);
        if (rankListModel != null) {
            LinkedList<ChannelTonBingRank> rankList = rankListModel.getRankList();
            if (!rankList.isEmpty()) {
                ChannelTonBingRank first = rankList.getFirst();
                userId = Long.parseLong(first.getId());
            }
        }
        return userId;
    }

    private long getMaxZhanGongUserId() {
        long userId = 0;
        ChannelTonBingRank first = userRank.getRankList().getFirst();
        if (first != null) {
            userId = Long.parseLong(first.getId());
        }
        return userId;
    }

    // ========= 预留方法 =========

    public void reloadConfig() {
        loadConfigFromDb(config.getActivityInfo());
    }

    public String hotCode(String param) {
        return "";
    }

    public int getUserCampId(long userId) {
        ChannelTonBingUserData userData = userDataMap.get(userId);
        if (userData == null) {
            return 0;
        }

        return userData.getCampId();
    }

    public List<Long> getLockUserIdsByServerId(long serverId, int channelId) {
        if (!channelTonBingDataMain.isLockUnion()) {
            return new ArrayList<>();
        }
        List<Long> userIds = new ArrayList<>();
        for (ChannelTonBingUserData userData : userDataMap.values()) {
            if (userData.getServerId() == serverId) {
                userIds.add(userData.getUserId());
            }
        }

        ChannelTonBingProto.CTonBingGetPromotionUserIdsRespMsg.Builder resp = ChannelTonBingProto.CTonBingGetPromotionUserIdsRespMsg.newBuilder();
        resp.setServerId(serverId);
        resp.addAllUserId(userIds);
        sendChannelPacket(GameProtocol.S_CTON_BING_GET_LOCK_USERIDS_BACK, resp, serverId, channelId);

        return userIds;
    }

}
